diff options
268 files changed, 4953 insertions, 1962 deletions
diff --git a/.github/workflows/javascript_builds.yml b/.github/workflows/javascript_builds.yml index ced2c36a91..7f7ebf680f 100644 --- a/.github/workflows/javascript_builds.yml +++ b/.github/workflows/javascript_builds.yml @@ -4,7 +4,7 @@ on: [push, pull_request] # Global Settings env: GODOT_BASE_BRANCH: master - SCONSFLAGS: platform=javascript verbose=yes warnings=extra debug_symbols=no --jobs=2 + SCONSFLAGS: platform=javascript verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 SCONS_CACHE_LIMIT: 4096 EM_VERSION: 2.0.25 EM_CACHE_FOLDER: 'emsdk-cache' diff --git a/SConstruct b/SConstruct index 5dec3f2020..0224784b9d 100644 --- a/SConstruct +++ b/SConstruct @@ -119,6 +119,7 @@ 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("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)) opts.Add(BoolVariable("use_lto", "Use link-time optimization", False)) @@ -201,7 +202,13 @@ elif env_base["p"] != "": selected_platform = env_base["p"] else: # Missing `platform` argument, try to detect platform automatically - if sys.platform.startswith("linux"): + if ( + sys.platform.startswith("linux") + or sys.platform.startswith("dragonfly") + or sys.platform.startswith("freebsd") + or sys.platform.startswith("netbsd") + or sys.platform.startswith("openbsd") + ): selected_platform = "linuxbsd" elif sys.platform == "darwin": selected_platform = "osx" @@ -321,6 +328,9 @@ if env_base["no_editor_splash"]: if not env_base["deprecated"]: env_base.Append(CPPDEFINES=["DISABLE_DEPRECATED"]) +if env_base["float"] == "64": + env_base.Append(CPPDEFINES=["REAL_T_IS_DOUBLE"]) + if selected_platform in platform_list: tmppath = "./platform/" + selected_platform sys.path.insert(0, tmppath) @@ -506,13 +516,17 @@ if selected_platform in platform_list: if env["werror"]: env.Append(CCFLAGS=["/WX"]) else: # GCC, Clang - gcc_common_warnings = [] + common_warnings = [] if methods.using_gcc(env): - gcc_common_warnings += ["-Wshadow-local", "-Wno-misleading-indentation"] + common_warnings += ["-Wshadow-local", "-Wno-misleading-indentation"] + elif methods.using_clang(env) or methods.using_emcc(env): + # We often implement `operator<` for structs of pointers as a requirement + # for putting them in `Set` or `Map`. We don't mind about unreliable ordering. + common_warnings += ["-Wno-ordered-compare-function-pointers"] if env["warnings"] == "extra": - env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + gcc_common_warnings) + env.Append(CCFLAGS=["-Wall", "-Wextra", "-Wwrite-strings", "-Wno-unused-parameter"] + common_warnings) env.Append(CXXFLAGS=["-Wctor-dtor-privacy", "-Wnon-virtual-dtor"]) if methods.using_gcc(env): env.Append( @@ -528,12 +542,12 @@ if selected_platform in platform_list: env.Append(CXXFLAGS=["-Wplacement-new=1"]) if cc_version_major >= 9: env.Append(CCFLAGS=["-Wattribute-alias=2"]) - elif methods.using_clang(env): + elif methods.using_clang(env) or methods.using_emcc(env): env.Append(CCFLAGS=["-Wimplicit-fallthrough"]) elif env["warnings"] == "all": - env.Append(CCFLAGS=["-Wall"] + gcc_common_warnings) + env.Append(CCFLAGS=["-Wall"] + common_warnings) elif env["warnings"] == "moderate": - env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + gcc_common_warnings) + env.Append(CCFLAGS=["-Wall", "-Wno-unused"] + common_warnings) else: # 'no' env.Append(CCFLAGS=["-w"]) @@ -544,7 +558,7 @@ if selected_platform in platform_list: env.Append(CXXFLAGS=["-Wno-error=cpp"]) if cc_version_major == 7: # Bogus warning fixed in 8+. env.Append(CCFLAGS=["-Wno-error=strict-overflow"]) - else: + elif methods.using_clang(env) or methods.using_emcc(env): env.Append(CXXFLAGS=["-Wno-error=#warnings"]) else: # always enable those errors env.Append(CCFLAGS=["-Werror=return-type"]) @@ -554,6 +568,9 @@ if selected_platform in platform_list: else: suffix = "." + selected_platform + if env_base["float"] == "64": + suffix += ".double" + if env["target"] == "release": if env["tools"]: print("Error: The editor can only be built with `target=debug` or `target=release_debug`.") diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 0b5b5627af..3ffd8ee46b 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -46,14 +46,14 @@ int Engine::get_iterations_per_second() const { return ips; } -void Engine::set_physics_jitter_fix(float p_threshold) { +void Engine::set_physics_jitter_fix(double p_threshold) { if (p_threshold < 0) { p_threshold = 0; } physics_jitter_fix = p_threshold; } -float Engine::get_physics_jitter_fix() const { +double Engine::get_physics_jitter_fix() const { return physics_jitter_fix; } @@ -77,11 +77,11 @@ uint32_t Engine::get_frame_delay() const { return _frame_delay; } -void Engine::set_time_scale(float p_scale) { +void Engine::set_time_scale(double p_scale) { _time_scale = p_scale; } -float Engine::get_time_scale() const { +double Engine::get_time_scale() const { return _time_scale; } diff --git a/core/config/engine.h b/core/config/engine.h index 970cfb03e8..3b3e5825b2 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -51,15 +51,15 @@ private: uint64_t frames_drawn = 0; uint32_t _frame_delay = 0; uint64_t _frame_ticks = 0; - float _process_step = 0; + double _process_step = 0; int ips = 60; - float physics_jitter_fix = 0.5; - float _fps = 1; + double physics_jitter_fix = 0.5; + double _fps = 1; int _target_fps = 0; - float _time_scale = 1.0; + double _time_scale = 1.0; uint64_t _physics_frames = 0; - float _physics_interpolation_fraction = 0.0f; + double _physics_interpolation_fraction = 0.0f; bool abort_on_gpu_errors = false; bool use_validation_layers = false; @@ -81,13 +81,13 @@ public: virtual void set_iterations_per_second(int p_ips); virtual int get_iterations_per_second() const; - void set_physics_jitter_fix(float p_threshold); - float get_physics_jitter_fix() const; + void set_physics_jitter_fix(double p_threshold); + double get_physics_jitter_fix() const; virtual void set_target_fps(int p_fps); virtual int get_target_fps() const; - virtual float get_frames_per_second() const { return _fps; } + virtual double get_frames_per_second() const { return _fps; } uint64_t get_frames_drawn(); @@ -95,11 +95,11 @@ public: uint64_t get_process_frames() const { return _process_frames; } bool is_in_physics_frame() const { return _in_physics; } uint64_t get_frame_ticks() const { return _frame_ticks; } - float get_process_step() const { return _process_step; } - float get_physics_interpolation_fraction() const { return _physics_interpolation_fraction; } + double get_process_step() const { return _process_step; } + double get_physics_interpolation_fraction() const { return _physics_interpolation_fraction; } - void set_time_scale(float p_scale); - float get_time_scale() const; + void set_time_scale(double p_scale); + double get_time_scale() const; void set_print_error_messages(bool p_enabled); bool is_printing_error_messages() const; diff --git a/core/core_bind.cpp b/core/core_bind.cpp index d34ed29691..76c918a92f 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -107,6 +107,10 @@ bool _ResourceLoader::exists(const String &p_path, const String &p_type_hint) { return ResourceLoader::exists(p_path, p_type_hint); } +ResourceUID::ID _ResourceLoader::get_resource_uid(const String &p_path) { + return ResourceLoader::get_resource_uid(p_path); +} + void _ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("load_threaded_request", "path", "type_hint", "use_sub_threads"), &_ResourceLoader::load_threaded_request, DEFVAL(""), DEFVAL(false)); ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &_ResourceLoader::load_threaded_get_status, DEFVAL(Array())); @@ -118,6 +122,7 @@ void _ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies); ClassDB::bind_method(D_METHOD("has_cached", "path"), &_ResourceLoader::has_cached); ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &_ResourceLoader::exists, DEFVAL("")); + ClassDB::bind_method(D_METHOD("get_resource_uid", "path"), &_ResourceLoader::get_resource_uid); BIND_ENUM_CONSTANT(THREAD_LOAD_INVALID_RESOURCE); BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS); @@ -356,7 +361,7 @@ void _OS::print_all_textures_by_size() { ResourceCache::get_cached_resources(&rsrc); for (Ref<Resource> &res : rsrc) { - if (!res->is_class("ImageTexture")) { + if (!res->is_class("Texture")) { continue; } @@ -376,14 +381,30 @@ void _OS::print_all_textures_by_size() { imgs.sort(); - for (_OSCoreBindImg &E : imgs) { - total -= E.vram; + if (imgs.size() == 0) { + print_line("No textures seem used in this project."); + } else { + print_line("Textures currently in use, sorted by VRAM usage:\n" + "Path - VRAM usage (Dimensions)"); } + + for (const _OSCoreBindImg &img : imgs) { + print_line(vformat("%s - %s %s", + img.path, + String::humanize_size(img.vram), + img.size)); + } + + print_line(vformat("Total VRAM usage: %s.", String::humanize_size(total))); } void _OS::print_resources_by_type(const Vector<String> &p_types) { - Map<String, int> type_count; + ERR_FAIL_COND_MSG(p_types.size() == 0, + "At least one type should be provided to print resources by type."); + print_line(vformat("Resources currently in use for the following types: %s", p_types)); + + Map<String, int> type_count; List<Ref<Resource>> resources; ResourceCache::get_cached_resources(&resources); @@ -404,6 +425,18 @@ void _OS::print_resources_by_type(const Vector<String> &p_types) { } type_count[r->get_class()]++; + + print_line(vformat("%s: %s", r->get_class(), r->get_path())); + + List<StringName> metas; + r->get_meta_list(&metas); + for (const StringName &meta : metas) { + print_line(vformat(" %s: %s", meta, r->get_meta(meta))); + } + } + + for (const KeyValue<String, int> &E : type_count) { + print_line(vformat("%s count: %d", E.key, E.value)); } } @@ -1759,7 +1792,7 @@ void _Thread::_start_func(void *ud) { target_param_count = method->get_argument_count(); target_default_arg_count = method->get_default_argument_count(); } - if (target_param_count >= 1 && target_default_arg_count == target_param_count) { + if (target_param_count >= 1 && target_default_arg_count < target_param_count) { argc = 1; } } @@ -2052,15 +2085,15 @@ int _Engine::get_iterations_per_second() const { return Engine::get_singleton()->get_iterations_per_second(); } -void _Engine::set_physics_jitter_fix(float p_threshold) { +void _Engine::set_physics_jitter_fix(double p_threshold) { Engine::get_singleton()->set_physics_jitter_fix(p_threshold); } -float _Engine::get_physics_jitter_fix() const { +double _Engine::get_physics_jitter_fix() const { return Engine::get_singleton()->get_physics_jitter_fix(); } -float _Engine::get_physics_interpolation_fraction() const { +double _Engine::get_physics_interpolation_fraction() const { return Engine::get_singleton()->get_physics_interpolation_fraction(); } @@ -2072,7 +2105,7 @@ int _Engine::get_target_fps() const { return Engine::get_singleton()->get_target_fps(); } -float _Engine::get_frames_per_second() const { +double _Engine::get_frames_per_second() const { return Engine::get_singleton()->get_frames_per_second(); } @@ -2084,11 +2117,11 @@ uint64_t _Engine::get_process_frames() const { return Engine::get_singleton()->get_process_frames(); } -void _Engine::set_time_scale(float p_scale) { +void _Engine::set_time_scale(double p_scale) { Engine::get_singleton()->set_time_scale(p_scale); } -float _Engine::get_time_scale() { +double _Engine::get_time_scale() { return Engine::get_singleton()->get_time_scale(); } @@ -2309,7 +2342,7 @@ void _EngineDebugger::call_add(void *p_user, const Array &p_data) { ERR_FAIL_COND_MSG(err.error != Callable::CallError::CALL_OK, "Error calling 'add' to callable: " + Variant::get_callable_error_text(add, args, 1, err)); } -void _EngineDebugger::call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { +void _EngineDebugger::call_tick(void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { Callable &tick = ((ProfilerCallable *)p_user)->callable_tick; if (tick.is_null()) { return; diff --git a/core/core_bind.h b/core/core_bind.h index 1574c36d3c..8736e6ffd8 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -75,6 +75,7 @@ public: PackedStringArray get_dependencies(const String &p_path); bool has_cached(const String &p_path); bool exists(const String &p_path, const String &p_type_hint = ""); + ResourceUID::ID get_resource_uid(const String &p_path); _ResourceLoader() { singleton = this; } }; @@ -625,21 +626,21 @@ public: void set_iterations_per_second(int p_ips); int get_iterations_per_second() const; - void set_physics_jitter_fix(float p_threshold); - float get_physics_jitter_fix() const; - float get_physics_interpolation_fraction() const; + void set_physics_jitter_fix(double p_threshold); + double get_physics_jitter_fix() const; + double get_physics_interpolation_fraction() const; void set_target_fps(int p_fps); int get_target_fps() const; - float get_frames_per_second() const; + double get_frames_per_second() const; uint64_t get_physics_frames() const; uint64_t get_process_frames() const; int get_frames_drawn(); - void set_time_scale(float p_scale); - float get_time_scale(); + void set_time_scale(double p_scale); + double get_time_scale(); MainLoop *get_main_loop() const; @@ -711,7 +712,7 @@ public: static void call_toggle(void *p_user, bool p_enable, const Array &p_opts); static void call_add(void *p_user, const Array &p_data); - static void call_tick(void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time); + static void call_tick(void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time); static Error call_capture(void *p_user, const String &p_cmd, const Array &p_data, bool &r_captured); _EngineDebugger() { singleton = this; } diff --git a/core/core_constants.cpp b/core/core_constants.cpp index d944ed6935..b09e78d653 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -133,6 +133,19 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(VALIGN_CENTER); BIND_CORE_ENUM_CONSTANT(VALIGN_BOTTOM); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TOP_TO); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_CENTER_TO); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_BOTTOM_TO); + + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_TOP); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_CENTER); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_BASELINE); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_BOTTOM); + + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TOP); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_CENTER); + BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_BOTTOM); + // huge list of keys BIND_CORE_CONSTANT(SPKEY); diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h index 3e8c34d84b..98ad2b98d1 100644 --- a/core/debugger/debugger_marshalls.h +++ b/core/debugger/debugger_marshalls.h @@ -83,14 +83,14 @@ struct DebuggerMarshalls { StringName name; int sig_id = -1; int call_count = 0; - float self_time = 0; - float total_time = 0; + double self_time = 0; + double total_time = 0; }; // Servers profiler struct ServerFunctionInfo { StringName name; - float time = 0; + double time = 0; }; struct ServerInfo { @@ -100,11 +100,11 @@ struct DebuggerMarshalls { struct ServersProfilerFrame { int frame_number = 0; - float frame_time = 0; - float idle_time = 0; - float physics_time = 0; - float physics_frame_time = 0; - float script_time = 0; + double frame_time = 0; + double idle_time = 0; + double physics_time = 0; + double physics_frame_time = 0; + double script_time = 0; List<ServerInfo> servers; Vector<ScriptFunctionInfo> script_functions; diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp index e5dba029c9..a522b1310f 100644 --- a/core/debugger/engine_debugger.cpp +++ b/core/debugger/engine_debugger.cpp @@ -117,7 +117,7 @@ void EngineDebugger::line_poll() { poll_every++; } -void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, float p_physics_frame_time) { +void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time) { frame_time = USEC_TO_SEC(p_frame_ticks); process_time = USEC_TO_SEC(p_process_ticks); physics_time = USEC_TO_SEC(p_physics_ticks); diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h index c6daea6e2f..22c6ef943e 100644 --- a/core/debugger/engine_debugger.h +++ b/core/debugger/engine_debugger.h @@ -44,7 +44,7 @@ class ScriptDebugger; class EngineDebugger { public: typedef void (*ProfilingToggle)(void *p_user, bool p_enable, const Array &p_opts); - typedef void (*ProfilingTick)(void *p_user, float p_frame_time, float p_process_time, float p_physics_time, float p_physics_frame_time); + typedef void (*ProfilingTick)(void *p_user, double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time); typedef void (*ProfilingAdd)(void *p_user, const Array &p_arr); typedef Error (*CaptureFunc)(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured); @@ -85,10 +85,10 @@ public: }; private: - float frame_time = 0.0; - float process_time = 0.0; - float physics_time = 0.0; - float physics_frame_time = 0.0; + double frame_time = 0.0; + double process_time = 0.0; + double physics_time = 0.0; + double physics_frame_time = 0.0; uint32_t poll_every = 0; @@ -120,7 +120,7 @@ public: static void register_uri_handler(const String &p_protocol, CreatePeerFunc p_func); - void iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, float p_physics_frame_time); + void iteration(uint64_t p_frame_ticks, uint64_t p_process_ticks, uint64_t p_physics_ticks, double p_physics_frame_time); void profiler_enable(const StringName &p_name, bool p_enabled, const Array &p_opts = Array()); Error capture_parse(const StringName &p_name, const String &p_msg, const Array &p_args, bool &r_captured); diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp index 24833711d5..b0b3f11424 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -41,7 +41,7 @@ struct LocalDebugger::ScriptsProfiler { } }; - float frame_time = 0; + double frame_time = 0; uint64_t idle_accum = 0; Vector<ScriptLanguage::ProfilingInfo> pinfo; @@ -61,7 +61,7 @@ struct LocalDebugger::ScriptsProfiler { } } - void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { frame_time = p_frame_time; _print_frame_data(false); } @@ -92,8 +92,8 @@ struct LocalDebugger::ScriptsProfiler { for (int i = 0; i < ofs; i++) { script_time_us += pinfo[i].self_time; } - float script_time = USEC_TO_SEC(script_time_us); - float total_time = p_accumulated ? script_time : frame_time; + double script_time = USEC_TO_SEC(script_time_us); + double total_time = p_accumulated ? script_time : frame_time; if (!p_accumulated) { print_line("FRAME: total: " + rtos(total_time) + " script: " + rtos(script_time) + "/" + itos(script_time * 100 / total_time) + " %"); @@ -103,8 +103,8 @@ struct LocalDebugger::ScriptsProfiler { for (int i = 0; i < ofs; i++) { print_line(itos(i) + ":" + pinfo[i].signature); - float tt = USEC_TO_SEC(pinfo[i].total_time); - float st = USEC_TO_SEC(pinfo[i].self_time); + double tt = USEC_TO_SEC(pinfo[i].total_time); + double st = USEC_TO_SEC(pinfo[i].self_time); print_line("\ttotal: " + rtos(tt) + "/" + itos(tt * 100 / total_time) + " % \tself: " + rtos(st) + "/" + itos(st * 100 / total_time) + " % tcalls: " + itos(pinfo[i].call_count)); } } @@ -373,7 +373,7 @@ LocalDebugger::LocalDebugger() { ((ScriptsProfiler *)p_user)->toggle(p_enable, p_opts); }, nullptr, - [](void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + [](void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { ((ScriptsProfiler *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time); }); register_profiler("scripts", scr_prof); diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 62d5126e57..f865dfe102 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -50,7 +50,7 @@ void RemoteDebugger::_bind_profiler(const String &p_name, T *p_prof) { [](void *p_user, const Array &p_data) { ((T *)p_user)->add(p_data); }, - [](void *p_user, float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + [](void *p_user, double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { ((T *)p_user)->tick(p_frame_time, p_idle_time, p_physics_time, p_physics_frame_time); }); EngineDebugger::register_profiler(p_name, prof); @@ -164,7 +164,7 @@ public: } } - void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { uint64_t pt = OS::get_singleton()->get_ticks_msec(); if (pt - last_bandwidth_time > 200) { last_bandwidth_time = pt; @@ -278,10 +278,10 @@ struct RemoteDebugger::ServersProfiler { Map<StringName, ServerInfo> server_data; ScriptsProfiler scripts_profiler; - float frame_time = 0; - float idle_time = 0; - float physics_time = 0; - float physics_frame_time = 0; + double frame_time = 0; + double idle_time = 0; + double physics_time = 0; + double physics_frame_time = 0; void toggle(bool p_enable, const Array &p_opts) { skip_profile_frame = false; @@ -308,7 +308,7 @@ struct RemoteDebugger::ServersProfiler { srv.functions.push_back(fi); } - void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { frame_time = p_frame_time; idle_time = p_idle_time; physics_time = p_physics_time; @@ -358,7 +358,7 @@ struct RemoteDebugger::VisualProfiler { void add(const Array &p_data) {} - void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { Vector<RS::FrameProfileArea> profile_areas = RS::get_singleton()->get_frame_profile(); DebuggerMarshalls::VisualProfilerFrame frame; if (!profile_areas.size()) { @@ -378,7 +378,7 @@ struct RemoteDebugger::PerformanceProfiler { void toggle(bool p_enable, const Array &p_opts) {} void add(const Array &p_data) {} - void tick(float p_frame_time, float p_idle_time, float p_physics_time, float p_physics_frame_time) { + void tick(double p_frame_time, double p_idle_time, double p_physics_time, double p_physics_frame_time) { if (!performance) { return; } diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 6714705bb5..15be0f1e36 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -196,7 +196,7 @@ Array InputMap::_action_get_events(const StringName &p_action) { 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()) { - ret.push_back(E); + ret.push_back(E->get()); } } diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index d21c0bd9a2..e6e79dff8a 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -316,52 +316,53 @@ String FileAccess::get_line() const { } Vector<String> FileAccess::get_csv_line(const String &p_delim) const { - ERR_FAIL_COND_V(p_delim.length() != 1, Vector<String>()); + ERR_FAIL_COND_V_MSG(p_delim.length() != 1, Vector<String>(), "Only single character delimiters are supported to parse CSV lines."); + ERR_FAIL_COND_V_MSG(p_delim[0] == '"', Vector<String>(), "The double quotation mark character (\") is not supported as a delimiter for CSV lines."); - String l; + String line; + + // CSV can support entries with line breaks as long as they are enclosed + // in double quotes. So our "line" might be more than a single line in the + // text file. int qc = 0; do { if (eof_reached()) { break; } - - l += get_line() + "\n"; + line += get_line() + "\n"; qc = 0; - for (int i = 0; i < l.length(); i++) { - if (l[i] == '"') { + for (int i = 0; i < line.length(); i++) { + if (line[i] == '"') { qc++; } } - } while (qc % 2); - l = l.substr(0, l.length() - 1); + // Remove the extraneous newline we've added above. + line = line.substr(0, line.length() - 1); Vector<String> strings; bool in_quote = false; String current; - for (int i = 0; i < l.length(); i++) { - char32_t c = l[i]; - char32_t s[2] = { 0, 0 }; - + for (int i = 0; i < line.length(); i++) { + char32_t c = line[i]; + // A delimiter ends the current entry, unless it's in a quoted string. if (!in_quote && c == p_delim[0]) { strings.push_back(current); current = String(); } else if (c == '"') { - if (l[i + 1] == '"' && in_quote) { - s[0] = '"'; - current += s; + // Doubled quotes are escapes for intentional quotes in the string. + if (line[i + 1] == '"' && in_quote) { + current += '"'; i++; } else { in_quote = !in_quote; } } else { - s[0] = c; - current += s; + current += c; } } - strings.push_back(current); return strings; diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 1c3f231170..f792dc6cb4 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -33,6 +33,7 @@ #include "core/debugger/engine_debugger.h" #include "core/io/marshalls.h" #include "scene/main/node.h" +#include "scene/resources/packed_scene.h" #include <stdint.h> @@ -146,6 +147,7 @@ void MultiplayerAPI::poll() { } void MultiplayerAPI::clear() { + replicated_nodes.clear(); connected_peers.clear(); path_get_cache.clear(); path_send_cache.clear(); @@ -322,6 +324,12 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ case NETWORK_COMMAND_RAW: { _process_raw(p_from, p_packet, p_packet_len); } break; + case NETWORK_COMMAND_SPAWN: { + _process_spawn_despawn(p_from, p_packet, p_packet_len, true); + } break; + case NETWORK_COMMAND_DESPAWN: { + _process_spawn_despawn(p_from, p_packet, p_packet_len, false); + } break; } } @@ -506,6 +514,64 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, E->get() = true; } +void MultiplayerAPI::_process_spawn_despawn(int p_from, const uint8_t *p_packet, int p_packet_len, bool p_spawn) { + ERR_FAIL_COND_MSG(p_packet_len < 18, "Invalid spawn packet received"); + int ofs = 1; + ResourceUID::ID id = decode_uint64(&p_packet[ofs]); + ofs += 8; + ERR_FAIL_COND_MSG(!spawnables.has(id), "Invalid spawn ID received " + itos(id)); + + uint32_t node_target = decode_uint32(&p_packet[ofs]); + Node *parent = _process_get_node(p_from, nullptr, node_target, 0); + ofs += 4; + ERR_FAIL_COND_MSG(parent == nullptr, "Invalid packet received. Requested node was not found."); + + uint32_t name_len = decode_uint32(&p_packet[ofs]); + ofs += 4; + ERR_FAIL_COND_MSG(name_len > uint32_t(p_packet_len - ofs), vformat("Invalid spawn packet size: %d, wants: %d", p_packet_len, ofs + name_len)); + ERR_FAIL_COND_MSG(name_len < 1, "Zero spawn name size."); + + const String name = String::utf8((const char *)&p_packet[ofs], name_len); + // We need to make sure no trickery happens here (e.g. despawning a subpath), but we want to allow autogenerated ("@") node names. + ERR_FAIL_COND_MSG(name.validate_node_name() != name.replace("@", ""), vformat("Invalid node name received: '%s'", name)); + ofs += name_len; + PackedByteArray data; + if (p_packet_len > ofs) { + data.resize(p_packet_len - ofs); + memcpy(data.ptrw(), &p_packet[ofs], data.size()); + } + + SpawnMode mode = spawnables[id]; + if (mode == SPAWN_MODE_SERVER && p_from == 1) { + String scene_path = ResourceUID::get_singleton()->get_id_path(id); + if (p_spawn) { + ERR_FAIL_COND_MSG(parent->has_node(name), vformat("Unable to spawn node. Node already exists: %s/%s", parent->get_path(), name)); + RES res = ResourceLoader::load(scene_path); + ERR_FAIL_COND_MSG(!res.is_valid(), "Unable to load scene to spawn at path: " + scene_path); + PackedScene *scene = Object::cast_to<PackedScene>(res.ptr()); + ERR_FAIL_COND(!scene); + Node *node = scene->instantiate(); + ERR_FAIL_COND(!node); + replicated_nodes[node->get_instance_id()] = id; + parent->_add_child_nocheck(node, name); + emit_signal(SNAME("network_spawn"), p_from, id, node, data); + } else { + ERR_FAIL_COND_MSG(!parent->has_node(name), vformat("Path not found: %s/%s", parent->get_path(), name)); + Node *node = parent->get_node(name); + ERR_FAIL_COND_MSG(!replicated_nodes.has(node->get_instance_id()), vformat("Trying to despawn a Node that was not replicated: %s/%s", parent->get_path(), name)); + emit_signal(SNAME("network_despawn"), p_from, id, node, data); + replicated_nodes.erase(node->get_instance_id()); + node->queue_delete(); + } + } else { + if (p_spawn) { + emit_signal(SNAME("network_spawn_request"), p_from, id, parent, name, data); + } else { + emit_signal(SNAME("network_despawn_request"), p_from, id, parent, name, data); + } + } +} + bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target) { bool has_all_peers = true; List<int> peers_to_add; // If one is missing, take note to add it. @@ -909,6 +975,16 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const void MultiplayerAPI::_add_peer(int p_id) { connected_peers.insert(p_id); path_get_cache.insert(p_id, PathGetCache()); + if (is_network_server()) { + for (const KeyValue<ObjectID, ResourceUID::ID> &E : replicated_nodes) { + // Only server mode adds to replicated_nodes, no need to check it. + Object *obj = ObjectDB::get_instance(E.key); + ERR_CONTINUE(!obj); + Node *node = Object::cast_to<Node>(obj); + ERR_CONTINUE(!node); + _send_spawn_despawn(p_id, E.value, node->get_path(), nullptr, 0, true); + } + } emit_signal(SNAME("network_peer_connected"), p_id); } @@ -924,6 +1000,10 @@ void MultiplayerAPI::_del_peer(int p_id) { PathSentCache *psc = path_send_cache.getptr(E); psc->confirmed_peers.erase(p_id); } + if (p_id == 1) { + // Erase server replicated nodes, but do not queue them for deletion. + replicated_nodes.clear(); + } emit_signal(SNAME("network_peer_disconnected"), p_id); } @@ -1067,6 +1147,99 @@ bool MultiplayerAPI::is_object_decoding_allowed() const { return allow_object_decoding; } +Error MultiplayerAPI::spawnable_config(const ResourceUID::ID &p_id, SpawnMode p_mode) { + ERR_FAIL_COND_V(p_mode < SPAWN_MODE_NONE || p_mode > SPAWN_MODE_CUSTOM, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!ResourceUID::get_singleton()->has_id(p_id), ERR_INVALID_PARAMETER); +#ifdef TOOLS_ENABLED + String path = ResourceUID::get_singleton()->get_id_path(p_id); + RES res = ResourceLoader::load(path); + ERR_FAIL_COND_V(!res->is_class("PackedScene"), ERR_INVALID_PARAMETER); +#endif + if (p_mode == SPAWN_MODE_NONE) { + if (spawnables.has(p_id)) { + spawnables.erase(p_id); + } + } else { + spawnables[p_id] = p_mode; + } + return OK; +} + +Error MultiplayerAPI::send_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const NodePath &p_path, const PackedByteArray &p_data) { + return _send_spawn_despawn(p_peer_id, p_scene_id, p_path, p_data.ptr(), p_data.size(), false); +} + +Error MultiplayerAPI::send_spawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const NodePath &p_path, const PackedByteArray &p_data) { + return _send_spawn_despawn(p_peer_id, p_scene_id, p_path, p_data.ptr(), p_data.size(), true); +} + +Error MultiplayerAPI::_send_spawn_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const NodePath &p_path, const uint8_t *p_data, int p_data_len, bool p_spawn) { + ERR_FAIL_COND_V(!root_node, ERR_UNCONFIGURED); + ERR_FAIL_COND_V_MSG(!spawnables.has(p_scene_id), ERR_INVALID_PARAMETER, vformat("Spawnable not found: %d", p_scene_id)); + + NodePath rel_path = (root_node->get_path()).rel_path_to(p_path); + const Vector<StringName> names = rel_path.get_names(); + ERR_FAIL_COND_V(names.size() < 2, ERR_INVALID_PARAMETER); + + NodePath parent = NodePath(names.subarray(0, names.size() - 2), false); + ERR_FAIL_COND_V_MSG(!root_node->has_node(parent), ERR_INVALID_PARAMETER, "Path not found: " + parent); + + // See if the path is cached. + PathSentCache *psc = path_send_cache.getptr(parent); + if (!psc) { + // Path is not cached, create. + path_send_cache[parent] = PathSentCache(); + psc = path_send_cache.getptr(parent); + psc->id = last_send_cache_id++; + } + _send_confirm_path(root_node->get_node(parent), parent, psc, p_peer_id); + + const CharString cname = String(names[names.size() - 1]).utf8(); + int nlen = encode_cstring(cname.get_data(), nullptr); + MAKE_ROOM(1 + 8 + 4 + 4 + nlen + p_data_len); + uint8_t *ptr = packet_cache.ptrw(); + ptr[0] = p_spawn ? NETWORK_COMMAND_SPAWN : NETWORK_COMMAND_DESPAWN; + int ofs = 1; + ofs += encode_uint64(p_scene_id, &ptr[ofs]); + ofs += encode_uint32(psc->id, &ptr[ofs]); + ofs += encode_uint32(nlen, &ptr[ofs]); + ofs += encode_cstring(cname.get_data(), &ptr[ofs]); + memcpy(&ptr[ofs], p_data, p_data_len); + network_peer->set_target_peer(p_peer_id); + network_peer->set_transfer_channel(0); + network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); + return network_peer->put_packet(ptr, ofs + p_data_len); +} + +void MultiplayerAPI::scene_enter_exit_notify(const String &p_scene, const Node *p_node, bool p_enter) { + if (!has_network_peer()) { + return; + } + ERR_FAIL_COND(!p_node || !p_node->get_parent() || !root_node); + NodePath path = (root_node->get_path()).rel_path_to(p_node->get_parent()->get_path()); + if (path.is_empty()) { + return; + } + ResourceUID::ID id = ResourceLoader::get_resource_uid(p_scene); + if (!spawnables.has(id)) { + return; + } + SpawnMode mode = spawnables[id]; + if (p_enter) { + if (mode == SPAWN_MODE_SERVER && is_network_server()) { + replicated_nodes[p_node->get_instance_id()] = id; + _send_spawn_despawn(0, id, p_node->get_path(), nullptr, 0, true); + } + emit_signal(SNAME("network_spawnable_added"), id, p_node); + } else { + if (mode == SPAWN_MODE_SERVER && is_network_server() && replicated_nodes.has(p_node->get_instance_id())) { + replicated_nodes.erase(p_node->get_instance_id()); + _send_spawn_despawn(0, id, p_node->get_path(), nullptr, 0, false); + } + emit_signal(SNAME("network_spawnable_removed"), id, p_node); + } +} + void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node); @@ -1085,6 +1258,9 @@ void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &MultiplayerAPI::is_refusing_new_network_connections); ClassDB::bind_method(D_METHOD("set_allow_object_decoding", "enable"), &MultiplayerAPI::set_allow_object_decoding); ClassDB::bind_method(D_METHOD("is_object_decoding_allowed"), &MultiplayerAPI::is_object_decoding_allowed); + ClassDB::bind_method(D_METHOD("spawnable_config", "scene_id", "spawn_mode"), &MultiplayerAPI::spawnable_config); + ClassDB::bind_method(D_METHOD("send_despawn", "peer_id", "scene_id", "path", "data"), &MultiplayerAPI::send_despawn, DEFVAL(PackedByteArray())); + ClassDB::bind_method(D_METHOD("send_spawn", "peer_id", "scene_id", "path", "data"), &MultiplayerAPI::send_spawn, DEFVAL(PackedByteArray())); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); @@ -1098,11 +1274,21 @@ void MultiplayerAPI::_bind_methods() { ADD_SIGNAL(MethodInfo("connected_to_server")); ADD_SIGNAL(MethodInfo("connection_failed")); ADD_SIGNAL(MethodInfo("server_disconnected")); + ADD_SIGNAL(MethodInfo("network_despawn", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data"))); + ADD_SIGNAL(MethodInfo("network_spawn", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data"))); + ADD_SIGNAL(MethodInfo("network_despawn_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data"))); + ADD_SIGNAL(MethodInfo("network_spawn_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "parent", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data"))); + ADD_SIGNAL(MethodInfo("network_spawnable_added", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("network_spawnable_removed", PropertyInfo(Variant::INT, "scene_id"), PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); BIND_ENUM_CONSTANT(RPC_MODE_DISABLED); BIND_ENUM_CONSTANT(RPC_MODE_REMOTE); BIND_ENUM_CONSTANT(RPC_MODE_MASTER); BIND_ENUM_CONSTANT(RPC_MODE_PUPPET); + + BIND_ENUM_CONSTANT(SPAWN_MODE_NONE); + BIND_ENUM_CONSTANT(SPAWN_MODE_SERVER); + BIND_ENUM_CONSTANT(SPAWN_MODE_CUSTOM); } MultiplayerAPI::MultiplayerAPI() { diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 011bc3dde9..9552a0bf35 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -32,6 +32,7 @@ #define MULTIPLAYER_API_H #include "core/io/multiplayer_peer.h" +#include "core/io/resource_uid.h" #include "core/object/ref_counted.h" class MultiplayerAPI : public RefCounted { @@ -45,6 +46,12 @@ public: RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets }; + enum SpawnMode { + SPAWN_MODE_NONE, + SPAWN_MODE_SERVER, + SPAWN_MODE_CUSTOM, + }; + struct RPCConfig { StringName name; RPCMode rpc_mode = RPC_MODE_DISABLED; @@ -82,10 +89,12 @@ private: }; Ref<MultiplayerPeer> network_peer; + Map<ResourceUID::ID, SpawnMode> spawnables; int rpc_sender_id = 0; Set<int> connected_peers; HashMap<NodePath, PathSentCache> path_send_cache; Map<int, PathGetCache> path_get_cache; + Map<ObjectID, ResourceUID::ID> replicated_nodes; int last_send_cache_id; Vector<uint8_t> packet_cache; Node *root_node = nullptr; @@ -97,6 +106,7 @@ protected: void _process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); void _process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len); void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len); + void _process_spawn_despawn(int p_from, const uint8_t *p_packet, int p_packet_len, bool p_spawn); Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len); @@ -113,6 +123,8 @@ public: NETWORK_COMMAND_SIMPLIFY_PATH, NETWORK_COMMAND_CONFIRM_PATH, NETWORK_COMMAND_RAW, + NETWORK_COMMAND_SPAWN, + NETWORK_COMMAND_DESPAWN, }; enum NetworkNodeIdCompression { @@ -154,10 +166,17 @@ public: void set_allow_object_decoding(bool p_enable); bool is_object_decoding_allowed() const; + Error spawnable_config(const ResourceUID::ID &p_id, SpawnMode p_mode); + Error send_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const NodePath &p_path, const PackedByteArray &p_data = PackedByteArray()); + Error send_spawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const NodePath &p_path, const PackedByteArray &p_data = PackedByteArray()); + Error _send_spawn_despawn(int p_peer_id, const ResourceUID::ID &p_scene_id, const NodePath &p_path, const uint8_t *p_data, int p_data_len, bool p_spawn); + void scene_enter_exit_notify(const String &p_scene, const Node *p_node, bool p_enter); + MultiplayerAPI(); ~MultiplayerAPI(); }; VARIANT_ENUM_CAST(MultiplayerAPI::RPCMode); +VARIANT_ENUM_CAST(MultiplayerAPI::SpawnMode); #endif // MULTIPLAYER_API_H diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 727611a573..0262655927 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -552,5 +552,7 @@ void ResourceCache::dump(const char *p_file, bool p_short) { } lock.read_unlock(); +#else + WARN_PRINT("ResourceCache::dump only with in debug builds."); #endif } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index aa3831d4cf..b5e25fb837 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -1129,3 +1129,21 @@ void Basis::rotate_sh(real_t *p_values) { p_values[7] = -d3; p_values[8] = d4 * s_scale_dst4; } + +Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(p_target.is_equal_approx(Vector3()), Basis(), "The target vector can't be zero."); + ERR_FAIL_COND_V_MSG(p_up.is_equal_approx(Vector3()), Basis(), "The up vector can't be zero."); +#endif + Vector3 v_z = -p_target.normalized(); + Vector3 v_x = p_up.cross(v_z); +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(v_x.is_equal_approx(Vector3()), Basis(), "The target vector and up vector can't be parallel to each other."); +#endif + v_x.normalize(); + Vector3 v_y = v_z.cross(v_x); + + Basis basis; + basis.set(v_x, v_y, v_z); + return basis; +} diff --git a/core/math/basis.h b/core/math/basis.h index 2889a4aa5e..3db2227b70 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -242,6 +242,8 @@ public: operator Quaternion() const { return get_quaternion(); } + static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }; Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); } diff --git a/core/math/math_defs.h b/core/math/math_defs.h index 7692e1be47..c3a8f910c0 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -81,6 +81,26 @@ enum VAlign { VALIGN_BOTTOM }; +enum InlineAlign { + // Image alignment points. + INLINE_ALIGN_TOP_TO = 0b0000, + INLINE_ALIGN_CENTER_TO = 0b0001, + INLINE_ALIGN_BOTTOM_TO = 0b0010, + INLINE_ALIGN_IMAGE_MASK = 0b0011, + + // Text alignment points. + INLINE_ALIGN_TO_TOP = 0b0000, + INLINE_ALIGN_TO_CENTER = 0b0100, + INLINE_ALIGN_TO_BASELINE = 0b1000, + INLINE_ALIGN_TO_BOTTOM = 0b1100, + INLINE_ALIGN_TEXT_MASK = 0b1100, + + // Presets. + INLINE_ALIGN_TOP = INLINE_ALIGN_TOP_TO | INLINE_ALIGN_TO_TOP, + INLINE_ALIGN_CENTER = INLINE_ALIGN_CENTER_TO | INLINE_ALIGN_TO_CENTER, + INLINE_ALIGN_BOTTOM = INLINE_ALIGN_BOTTOM_TO | INLINE_ALIGN_TO_BOTTOM +}; + enum Side { SIDE_LEFT, SIDE_TOP, diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index 51766b39f4..4f4943c8ef 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -71,40 +71,12 @@ void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) { Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { Transform3D t = *this; - t.set_look_at(origin, p_target, p_up); + t.basis = Basis::looking_at(p_target - origin, p_up); return t; } void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { -#ifdef MATH_CHECKS - ERR_FAIL_COND(p_eye == p_target); - ERR_FAIL_COND(p_up.length() == 0); -#endif - // Reference: MESA source code - Vector3 v_x, v_y, v_z; - - /* Make rotation matrix */ - - /* Z vector */ - v_z = p_eye - p_target; - - v_z.normalize(); - - v_y = p_up; - - v_x = v_y.cross(v_z); -#ifdef MATH_CHECKS - ERR_FAIL_COND(v_x.length() == 0); -#endif - - /* Recompute Y = Z cross X */ - v_y = v_z.cross(v_x); - - v_x.normalize(); - v_y.normalize(); - - basis.set(v_x, v_y, v_z); - + basis = Basis::looking_at(p_target - p_eye, p_up); origin = p_eye; } diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h index 3d8e70cec7..cadfdc13d1 100644 --- a/core/math/transform_3d.h +++ b/core/math/transform_3d.h @@ -75,16 +75,24 @@ public: bool operator!=(const Transform3D &p_transform) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; + _FORCE_INLINE_ AABB xform(const AABB &p_aabb) const; + _FORCE_INLINE_ Vector<Vector3> xform(const Vector<Vector3> &p_array) const; + + // NOTE: These are UNSAFE with non-uniform scaling, and will produce incorrect results. + // They use the transpose. + // For safe inverse transforms, xform by the affine_inverse. _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; + _FORCE_INLINE_ AABB xform_inv(const AABB &p_aabb) const; + _FORCE_INLINE_ Vector<Vector3> xform_inv(const Vector<Vector3> &p_array) const; + // Safe with non-uniform scaling (uses affine_inverse). _FORCE_INLINE_ Plane xform(const Plane &p_plane) const; _FORCE_INLINE_ Plane xform_inv(const Plane &p_plane) const; - _FORCE_INLINE_ AABB xform(const AABB &p_aabb) const; - _FORCE_INLINE_ AABB xform_inv(const AABB &p_aabb) const; - - _FORCE_INLINE_ Vector<Vector3> xform(const Vector<Vector3> &p_array) const; - _FORCE_INLINE_ Vector<Vector3> xform_inv(const Vector<Vector3> &p_array) const; + // These fast versions use precomputed affine inverse, and should be used in bottleneck areas where + // multiple planes are to be transformed. + _FORCE_INLINE_ Plane xform_fast(const Plane &p_plane, const Basis &p_basis_inverse_transpose) const; + static _FORCE_INLINE_ Plane xform_inv_fast(const Plane &p_plane, const Transform3D &p_inverse, const Basis &p_basis_transpose); void operator*=(const Transform3D &p_transform); Transform3D operator*(const Transform3D &p_transform) const; @@ -130,30 +138,20 @@ _FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const { (basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z)); } +// Neither the plane regular xform or xform_inv are particularly efficient, +// as they do a basis inverse. For xforming a large number +// of planes it is better to pre-calculate the inverse transpose basis once +// and reuse it for each plane, by using the 'fast' version of the functions. _FORCE_INLINE_ Plane Transform3D::xform(const Plane &p_plane) const { - Vector3 point = p_plane.normal * p_plane.d; - Vector3 point_dir = point + p_plane.normal; - point = xform(point); - point_dir = xform(point_dir); - - Vector3 normal = point_dir - point; - normal.normalize(); - real_t d = normal.dot(point); - - return Plane(normal, d); + Basis b = basis.inverse(); + b.transpose(); + return xform_fast(p_plane, b); } _FORCE_INLINE_ Plane Transform3D::xform_inv(const Plane &p_plane) const { - Vector3 point = p_plane.normal * p_plane.d; - Vector3 point_dir = point + p_plane.normal; - point = xform_inv(point); - point_dir = xform_inv(point_dir); - - Vector3 normal = point_dir - point; - normal.normalize(); - real_t d = normal.dot(point); - - return Plane(normal, d); + Transform3D inv = affine_inverse(); + Basis basis_transpose = basis.transposed(); + return xform_inv_fast(p_plane, inv, basis_transpose); } _FORCE_INLINE_ AABB Transform3D::xform(const AABB &p_aabb) const { @@ -231,4 +229,37 @@ Vector<Vector3> Transform3D::xform_inv(const Vector<Vector3> &p_array) const { return array; } +_FORCE_INLINE_ Plane Transform3D::xform_fast(const Plane &p_plane, const Basis &p_basis_inverse_transpose) const { + // Transform a single point on the plane. + Vector3 point = p_plane.normal * p_plane.d; + point = xform(point); + + // Use inverse transpose for correct normals with non-uniform scaling. + Vector3 normal = p_basis_inverse_transpose.xform(p_plane.normal); + normal.normalize(); + + real_t d = normal.dot(point); + return Plane(normal, d); +} + +_FORCE_INLINE_ Plane Transform3D::xform_inv_fast(const Plane &p_plane, const Transform3D &p_inverse, const Basis &p_basis_transpose) { + // Transform a single point on the plane. + Vector3 point = p_plane.normal * p_plane.d; + point = p_inverse.xform(point); + + // 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 = p_basis_transpose.xform(p_plane.normal); + normal.normalize(); + + real_t d = normal.dot(point); + return Plane(normal, d); +} + #endif // TRANSFORM_H diff --git a/core/os/os.cpp b/core/os/os.cpp index cdb570bb73..76a6da51e1 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -178,7 +178,7 @@ static void _OS_printres(Object *p_obj) { return; } - String str = itos(res->get_instance_id()) + String(res->get_class()) + ":" + String(res->get_name()) + " - " + res->get_path(); + String str = vformat("%s - %s - %s", res->to_string(), res->get_name(), res->get_path()); if (_OSPRF) { _OSPRF->store_line(str); } else { diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 19d23fd375..cb7d924556 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -929,6 +929,66 @@ void Translation::_bind_methods() { /////////////////////////////////////////////// +struct _character_accent_pair { + const char32_t character; + const char32_t *accented_character; +}; + +static _character_accent_pair _character_to_accented[] = { + { 'A', U"Å" }, + { 'B', U"ß" }, + { 'C', U"Ç" }, + { 'D', U"Ð" }, + { 'E', U"É" }, + { 'F', U"F́" }, + { 'G', U"Ĝ" }, + { 'H', U"Ĥ" }, + { 'I', U"Ĩ" }, + { 'J', U"Ĵ" }, + { 'K', U"ĸ" }, + { 'L', U"Ł" }, + { 'M', U"Ḿ" }, + { 'N', U"й" }, + { 'O', U"Ö" }, + { 'P', U"Ṕ" }, + { 'Q', U"Q́" }, + { 'R', U"Ř" }, + { 'S', U"Ŝ" }, + { 'T', U"Ŧ" }, + { 'U', U"Ũ" }, + { 'V', U"Ṽ" }, + { 'W', U"Ŵ" }, + { 'X', U"X́" }, + { 'Y', U"Ÿ" }, + { 'Z', U"Ž" }, + { 'a', U"á" }, + { 'b', U"ḅ" }, + { 'c', U"ć" }, + { 'd', U"d́" }, + { 'e', U"é" }, + { 'f', U"f́" }, + { 'g', U"ǵ" }, + { 'h', U"h̀" }, + { 'i', U"í" }, + { 'j', U"ǰ" }, + { 'k', U"ḱ" }, + { 'l', U"ł" }, + { 'm', U"m̀" }, + { 'n', U"ή" }, + { 'o', U"ô" }, + { 'p', U"ṕ" }, + { 'q', U"q́" }, + { 'r', U"ŕ" }, + { 's', U"š" }, + { 't', U"ŧ" }, + { 'u', U"ü" }, + { 'v', U"ṽ" }, + { 'w', U"ŵ" }, + { 'x', U"x́" }, + { 'y', U"ý" }, + { 'z', U"ź" }, +}; + bool TranslationServer::is_locale_valid(const String &p_locale) { const char **ptr = locale_list; @@ -1101,10 +1161,10 @@ StringName TranslationServer::translate(const StringName &p_message, const Strin } if (!res) { - return p_message; + return pseudolocalization_enabled ? pseudolocalize(p_message) : p_message; } - return res; + return pseudolocalization_enabled ? pseudolocalize(res) : res; } StringName TranslationServer::translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { @@ -1217,7 +1277,18 @@ void TranslationServer::setup() { } else { set_locale(OS::get_singleton()->get_locale()); } + fallback = GLOBAL_DEF("internationalization/locale/fallback", "en"); + pseudolocalization_enabled = GLOBAL_DEF("internationalization/pseudolocalization/use_pseudolocalization", false); + pseudolocalization_accents_enabled = GLOBAL_DEF("internationalization/pseudolocalization/replace_with_accents", true); + pseudolocalization_double_vowels_enabled = GLOBAL_DEF("internationalization/pseudolocalization/double_vowels", false); + pseudolocalization_fake_bidi_enabled = GLOBAL_DEF("internationalization/pseudolocalization/fake_bidi", false); + pseudolocalization_override_enabled = GLOBAL_DEF("internationalization/pseudolocalization/override", false); + expansion_ratio = GLOBAL_DEF("internationalization/pseudolocalization/expansion_ratio", 0.0); + pseudolocalization_prefix = GLOBAL_DEF("internationalization/pseudolocalization/prefix", "["); + pseudolocalization_suffix = GLOBAL_DEF("internationalization/pseudolocalization/suffix", "]"); + pseudolocalization_skip_placeholders_enabled = GLOBAL_DEF("internationalization/pseudolocalization/skip_placeholders", true); + #ifdef TOOLS_ENABLED { String options = ""; @@ -1258,10 +1329,10 @@ StringName TranslationServer::tool_translate(const StringName &p_message, const if (tool_translation.is_valid()) { StringName r = tool_translation->get_message(p_message, p_context); if (r) { - return r; + return editor_pseudolocalization ? tool_pseudolocalize(r) : r; } } - return p_message; + return editor_pseudolocalization ? tool_pseudolocalize(p_message) : p_message; } StringName TranslationServer::tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context) const { @@ -1306,6 +1377,181 @@ StringName TranslationServer::doc_translate_plural(const StringName &p_message, return p_message_plural; } +bool TranslationServer::is_pseudolocalization_enabled() const { + return pseudolocalization_enabled; +} + +void TranslationServer::set_pseudolocalization_enabled(bool p_enabled) { + pseudolocalization_enabled = p_enabled; + + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); + } + ResourceLoader::reload_translation_remaps(); +} + +void TranslationServer::set_editor_pseudolocalization(bool p_enabled) { + editor_pseudolocalization = p_enabled; +} + +void TranslationServer::reload_pseudolocalization() { + pseudolocalization_accents_enabled = GLOBAL_GET("internationalization/pseudolocalization/replace_with_accents"); + pseudolocalization_double_vowels_enabled = GLOBAL_GET("internationalization/pseudolocalization/double_vowels"); + pseudolocalization_fake_bidi_enabled = GLOBAL_GET("internationalization/pseudolocalization/fake_bidi"); + pseudolocalization_override_enabled = GLOBAL_GET("internationalization/pseudolocalization/override"); + expansion_ratio = GLOBAL_GET("internationalization/pseudolocalization/expansion_ratio"); + pseudolocalization_prefix = GLOBAL_GET("internationalization/pseudolocalization/prefix"); + pseudolocalization_suffix = GLOBAL_GET("internationalization/pseudolocalization/suffix"); + pseudolocalization_skip_placeholders_enabled = GLOBAL_GET("internationalization/pseudolocalization/skip_placeholders"); + + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED); + } + ResourceLoader::reload_translation_remaps(); +} + +StringName TranslationServer::pseudolocalize(const StringName &p_message) const { + String message = p_message; + int length = message.length(); + if (pseudolocalization_override_enabled) { + message = get_override_string(message); + } + + if (pseudolocalization_double_vowels_enabled) { + message = double_vowels(message); + } + + if (pseudolocalization_accents_enabled) { + message = replace_with_accented_string(message); + } + + if (pseudolocalization_fake_bidi_enabled) { + message = wrap_with_fakebidi_characters(message); + } + + StringName res = add_padding(message, length); + return res; +} + +StringName TranslationServer::tool_pseudolocalize(const StringName &p_message) const { + String message = p_message; + message = double_vowels(message); + message = replace_with_accented_string(message); + StringName res = "[!!! " + message + " !!!]"; + return res; +} + +String TranslationServer::get_override_string(String &p_message) const { + String res; + for (int i = 0; i < p_message.size(); i++) { + if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { + res += p_message[i]; + res += p_message[i + 1]; + i++; + continue; + } + res += '*'; + } + return res; +} + +String TranslationServer::double_vowels(String &p_message) const { + String res; + for (int i = 0; i < p_message.size(); i++) { + if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { + res += p_message[i]; + res += p_message[i + 1]; + i++; + continue; + } + res += p_message[i]; + if (p_message[i] == 'a' || p_message[i] == 'e' || p_message[i] == 'i' || p_message[i] == 'o' || p_message[i] == 'u' || + p_message[i] == 'A' || p_message[i] == 'E' || p_message[i] == 'I' || p_message[i] == 'O' || p_message[i] == 'U') { + res += p_message[i]; + } + } + return res; +}; + +String TranslationServer::replace_with_accented_string(String &p_message) const { + String res; + for (int i = 0; i < p_message.size(); i++) { + if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { + res += p_message[i]; + res += p_message[i + 1]; + i++; + continue; + } + const char32_t *accented = get_accented_version(p_message[i]); + if (accented) { + res += accented; + } else { + res += p_message[i]; + } + } + return res; +} + +String TranslationServer::wrap_with_fakebidi_characters(String &p_message) const { + String res; + char32_t fakebidiprefix = U'\u202e'; + char32_t fakebidisuffix = U'\u202c'; + res += fakebidiprefix; + // The fake bidi unicode gets popped at every newline so pushing it back at every newline. + for (int i = 0; i < p_message.size(); i++) { + if (p_message[i] == '\n') { + res += fakebidisuffix; + res += p_message[i]; + res += fakebidiprefix; + } else if (pseudolocalization_skip_placeholders_enabled && is_placeholder(p_message, i)) { + res += fakebidisuffix; + res += p_message[i]; + res += p_message[i + 1]; + res += fakebidiprefix; + i++; + } else { + res += p_message[i]; + } + } + res += fakebidisuffix; + return res; +} + +String TranslationServer::add_padding(String &p_message, int p_length) const { + String res; + String prefix = pseudolocalization_prefix; + String suffix; + for (int i = 0; i < p_length * expansion_ratio / 2; i++) { + prefix += "_"; + suffix += "_"; + } + suffix += pseudolocalization_suffix; + res += prefix; + res += p_message; + res += suffix; + return res; +} + +const char32_t *TranslationServer::get_accented_version(char32_t p_character) const { + if (!((p_character >= 'a' && p_character <= 'z') || (p_character >= 'A' && p_character <= 'Z'))) { + return nullptr; + } + + for (unsigned int i = 0; i < sizeof(_character_to_accented) / sizeof(_character_to_accented[0]); i++) { + if (_character_to_accented[i].character == p_character) { + return _character_to_accented[i].accented_character; + } + } + + return nullptr; +} + +bool TranslationServer::is_placeholder(String &p_message, int p_index) const { + return p_message[p_index] == '%' && p_index < p_message.size() - 1 && + (p_message[p_index + 1] == 's' || p_message[p_index + 1] == 'c' || p_message[p_index + 1] == 'd' || + p_message[p_index + 1] == 'o' || p_message[p_index + 1] == 'x' || p_message[p_index + 1] == 'X' || p_message[p_index + 1] == 'f'); +} + void TranslationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_locale", "locale"), &TranslationServer::set_locale); ClassDB::bind_method(D_METHOD("get_locale"), &TranslationServer::get_locale); @@ -1322,6 +1568,12 @@ void TranslationServer::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &TranslationServer::clear); ClassDB::bind_method(D_METHOD("get_loaded_locales"), &TranslationServer::get_loaded_locales); + + ClassDB::bind_method(D_METHOD("is_pseudolocalization_enabled"), &TranslationServer::is_pseudolocalization_enabled); + ClassDB::bind_method(D_METHOD("set_pseudolocalization_enabled", "enabled"), &TranslationServer::set_pseudolocalization_enabled); + ClassDB::bind_method(D_METHOD("reload_pseudolocalization"), &TranslationServer::reload_pseudolocalization); + ClassDB::bind_method(D_METHOD("pseudolocalize", "message"), &TranslationServer::pseudolocalize); + ADD_PROPERTY(PropertyInfo(Variant::Type::BOOL, "pseudolocalization_enabled"), "set_pseudolocalization_enabled", "is_pseudolocalization_enabled"); } void TranslationServer::load_translations() { diff --git a/core/string/translation.h b/core/string/translation.h index 72a828227e..4f179ac0fe 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -77,6 +77,26 @@ class TranslationServer : public Object { bool enabled = true; + bool pseudolocalization_enabled = false; + bool pseudolocalization_accents_enabled = false; + bool pseudolocalization_double_vowels_enabled = false; + bool pseudolocalization_fake_bidi_enabled = false; + bool pseudolocalization_override_enabled = false; + bool pseudolocalization_skip_placeholders_enabled = false; + bool editor_pseudolocalization = false; + float expansion_ratio = 0.0; + String pseudolocalization_prefix; + String pseudolocalization_suffix; + + StringName tool_pseudolocalize(const StringName &p_message) const; + String get_override_string(String &p_message) const; + String double_vowels(String &p_message) const; + String replace_with_accented_string(String &p_message) const; + String wrap_with_fakebidi_characters(String &p_message) const; + String add_padding(String &p_message, int p_length) const; + const char32_t *get_accented_version(char32_t p_character) const; + bool is_placeholder(String &p_message, int p_index) const; + static TranslationServer *singleton; bool _load_translations(const String &p_from); @@ -104,6 +124,13 @@ public: StringName translate(const StringName &p_message, const StringName &p_context = "") const; StringName translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; + StringName pseudolocalize(const StringName &p_message) const; + + bool is_pseudolocalization_enabled() const; + void set_pseudolocalization_enabled(bool p_enabled); + void set_editor_pseudolocalization(bool p_enabled); + void reload_pseudolocalization(); + static Vector<String> get_all_locales(); static Vector<String> get_all_locale_names(); static bool is_locale_valid(const String &p_locale); diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 3cb2a6bfb5..001da3ddcb 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -101,6 +101,7 @@ VARIANT_ENUM_CAST(MouseButton); VARIANT_ENUM_CAST(Orientation); VARIANT_ENUM_CAST(HAlign); VARIANT_ENUM_CAST(VAlign); +VARIANT_ENUM_CAST(InlineAlign); VARIANT_ENUM_CAST(PropertyHint); VARIANT_ENUM_CAST(PropertyUsageFlags); VARIANT_ENUM_CAST(Variant::Type); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 8bcc726af3..c3481d4896 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1728,6 +1728,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, slerp, sarray("to", "weight"), varray()); bind_method(Basis, is_equal_approx, sarray("b"), varray()); bind_method(Basis, get_rotation_quaternion, sarray(), varray()); + bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); /* AABB */ diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 1299977153..e78c3d97ae 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -1128,6 +1128,36 @@ <constant name="VALIGN_BOTTOM" value="2" enum="VAlign"> Vertical bottom alignment, usually for text-derived classes. </constant> + <constant name="INLINE_ALIGN_TOP_TO" value="0" enum="InlineAlign"> + Aligns the top of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGN_TO_*[/code] constant. + </constant> + <constant name="INLINE_ALIGN_CENTER_TO" value="1" enum="InlineAlign"> + Aligns the center of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGN_TO_*[/code] constant. + </constant> + <constant name="INLINE_ALIGN_BOTTOM_TO" value="2" enum="InlineAlign"> + Aligns the bottom of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGN_TO_*[/code] constant. + </constant> + <constant name="INLINE_ALIGN_TO_TOP" value="0" enum="InlineAlign"> + Aligns the position of the inline object (e.g. image, table) specified by [code]INLINE_ALIGN_*_TO[/code] constant to the top of the text. + </constant> + <constant name="INLINE_ALIGN_TO_CENTER" value="4" enum="InlineAlign"> + Aligns the position of the inline object (e.g. image, table) specified by [code]INLINE_ALIGN_*_TO[/code] constant to the center of the text. + </constant> + <constant name="INLINE_ALIGN_TO_BASELINE" value="8" enum="InlineAlign"> + Aligns the position of the inline object (e.g. image, table) specified by [code]INLINE_ALIGN_*_TO[/code] constant to the baseline of the text. + </constant> + <constant name="INLINE_ALIGN_TO_BOTTOM" value="12" enum="InlineAlign"> + Aligns inline object (e.g. image, table) to the bottom of the text. + </constant> + <constant name="INLINE_ALIGN_TOP" value="0" enum="InlineAlign"> + Aligns top of the inline object (e.g. image, table) to the top of the text. Equvalent to [code]INLINE_ALIGN_TOP_TO | INLINE_ALIGN_TO_TOP[/code]. + </constant> + <constant name="INLINE_ALIGN_CENTER" value="5" enum="InlineAlign"> + Aligns center of the inline object (e.g. image, table) to the center of the text. Equvalent to [code]INLINE_ALIGN_CENTER_TO | INLINE_ALIGN_TO_CENTER[/code]. + </constant> + <constant name="INLINE_ALIGN_BOTTOM" value="14" enum="InlineAlign"> + Aligns bottom of the inline object (e.g. image, table) to the bottom of the text. Equvalent to [code]INLINE_ALIGN_BOTTOM_TO | INLINE_ALIGN_TO_BOTTOM[/code]. + </constant> <constant name="SPKEY" value="16777216"> Keycodes with this bit applied are non-printable. </constant> diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index 12a13ecfcc..66fa57cb52 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -311,8 +311,8 @@ <member name="device" type="String" setter="set_device" getter="get_device" default=""Default""> Name of the current device for audio output (see [method get_device_list]). </member> - <member name="global_rate_scale" type="float" setter="set_global_rate_scale" getter="get_global_rate_scale" default="1.0"> - Scales the rate at which audio is played (i.e. setting it to [code]0.5[/code] will make the audio be played twice as fast). + <member name="playback_speed_scale" type="float" setter="set_playback_speed_scale" getter="get_playback_speed_scale" default="1.0"> + Scales the rate at which audio is played (i.e. setting it to [code]0.5[/code] will make the audio be played at half its speed). </member> </members> <signals> diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 9a4dd15c63..8fab84d885 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -109,6 +109,15 @@ Returns [code]true[/code] if this basis and [code]b[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component. </description> </method> + <method name="looking_at" qualifiers="static"> + <return type="Basis" /> + <argument index="0" name="target" type="Vector3" /> + <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> + <description> + Creates a Basis with a rotation such that the forward axis (-Z) points towards the [code]target[/code] position. + The up axis (+Y) points as close to the [code]up[/code] vector as possible while staying perpendicular to the forward axis. The resulting Basis is orthonormalized. The [code]target[/code] and [code]up[/code] vectors cannot be zero, and cannot be parallel to each other. + </description> + </method> <method name="operator !=" qualifiers="operator"> <return type="bool" /> <argument index="0" name="right" type="Basis" /> diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml index 1ace7ee6bf..b73aba50fd 100644 --- a/doc/classes/CharacterBody2D.xml +++ b/doc/classes/CharacterBody2D.xml @@ -79,6 +79,7 @@ Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision]. + When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions. </description> </method> </methods> diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml index 577ab5e84c..4cb4f9a850 100644 --- a/doc/classes/CharacterBody3D.xml +++ b/doc/classes/CharacterBody3D.xml @@ -65,6 +65,7 @@ Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision]. + When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions. </description> </method> </methods> diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml index 085568466a..62fd7a1d6e 100644 --- a/doc/classes/EditorInspectorPlugin.xml +++ b/doc/classes/EditorInspectorPlugin.xml @@ -13,6 +13,7 @@ On each of these calls, the "add" functions can be called. </description> <tutorials> + <link title="Inspector plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/inspector_plugins.html</link> </tutorials> <methods> <method name="_can_handle" qualifiers="virtual"> @@ -56,7 +57,7 @@ <return type="void" /> <argument index="0" name="control" type="Control" /> <description> - Adds a custom control, not necessarily a property editor. + Adds a custom control, which is not necessarily a property editor. </description> </method> <method name="add_property_editor"> @@ -64,7 +65,7 @@ <argument index="0" name="property" type="String" /> <argument index="1" name="editor" type="Control" /> <description> - Adds a property editor, this must inherit [EditorProperty]. + Adds a property editor for an individual property. The [code]editor[/code] control must extend [EditorProperty]. </description> </method> <method name="add_property_editor_for_multiple_properties"> @@ -73,7 +74,7 @@ <argument index="1" name="properties" type="PackedStringArray" /> <argument index="2" name="editor" type="Control" /> <description> - Adds an editor that allows modifying multiple properties, this must inherit [EditorProperty]. + Adds an editor that allows modifying multiple properties. The [code]editor[/code] control must extend [EditorProperty]. </description> </method> </methods> diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index 41f42568ad..725b0ba8ff 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -47,14 +47,14 @@ <method name="get_tooltip_text" qualifiers="const"> <return type="String" /> <description> - Override if you want to allow a custom tooltip over your property. + Must be implemented to provide a custom tooltip to the property editor. </description> </method> <method name="set_bottom_editor"> <return type="void" /> <argument index="0" name="editor" type="Control" /> <description> - Adds controls with this function if you want them on the bottom (below the label). + Puts the [code]editor[/code] control below the property label. The control must be previously added using [method Node.add_child]. </description> </method> </methods> diff --git a/doc/classes/File.xml b/doc/classes/File.xml index de3beedf0f..6622619fb3 100644 --- a/doc/classes/File.xml +++ b/doc/classes/File.xml @@ -119,8 +119,15 @@ <return type="PackedStringArray" /> <argument index="0" name="delim" type="String" default="","" /> <description> - Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [code]delim[/code] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long. - Text is interpreted as being UTF-8 encoded. + Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [code]delim[/code] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long, and cannot be a double quotation mark. + Text is interpreted as being UTF-8 encoded. Text values must be enclosed in double quotes if they include the delimiter character. Double quotes within a text value can be escaped by doubling their occurrence. + For example, the following CSV lines are valid and will be properly parsed as two strings each: + [codeblock] + Alice,"Hello, Bob!" + Bob,Alice! What a surprise! + Alice,"I thought you'd reply with ""Hello, world""." + [/codeblock] + Note how the second line can omit the enclosing quotes as it does not include the delimiter. However it [i]could[/i] very well use quotes, it was only written without for demonstration purposes. The third line must use [code]""[/code] for each quotation mark that needs to be interpreted as such instead of the end of a text value. </description> </method> <method name="get_double" qualifiers="const"> diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index 552e0fce4c..b9f50ad02a 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -66,6 +66,34 @@ Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method MultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers. </description> </method> + <method name="send_despawn"> + <return type="int" enum="Error" /> + <argument index="0" name="peer_id" type="int" /> + <argument index="1" name="scene_id" type="int" /> + <argument index="2" name="path" type="NodePath" /> + <argument index="3" name="data" type="PackedByteArray" default="PackedByteArray()" /> + <description> + Sends a despawn request for the scene identified by [code]scene_id[/code] to the given [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). If the scene is configured as [constant SPAWN_MODE_SERVER] (see [method spawnable_config]) and the request is sent by the server (see [method is_network_server]), the receiving peer(s) will automatically queue for deletion the node at [code]path[/code] and emit the signal [signal network_despawn]. In all other cases no deletion happens, and the signal [signal network_despawn_request] is emitted instead. + </description> + </method> + <method name="send_spawn"> + <return type="int" enum="Error" /> + <argument index="0" name="peer_id" type="int" /> + <argument index="1" name="scene_id" type="int" /> + <argument index="2" name="path" type="NodePath" /> + <argument index="3" name="data" type="PackedByteArray" default="PackedByteArray()" /> + <description> + Sends a spawn request for the scene identified by [code]scene_id[/code] to the given [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). If the scene is configured as [constant SPAWN_MODE_SERVER] (see [method spawnable_config]) and the request is sent by the server (see [method is_network_server]), the receiving peer(s) will automatically instantiate that scene, add it to the [SceneTree] at the given [code]path[/code] and emit the signal [signal network_spawn]. In all other cases no instantiation happens, and the signal [signal network_spawn_request] is emitted instead. + </description> + </method> + <method name="spawnable_config"> + <return type="int" enum="Error" /> + <argument index="0" name="scene_id" type="int" /> + <argument index="1" name="spawn_mode" type="int" enum="MultiplayerAPI.SpawnMode" /> + <description> + Configures the MultiplayerAPI to track instances of the [PackedScene] idenfied by [code]scene_id[/code] (see [method ResourceLoader.get_resource_uid]) for the purpose of network replication. See [enum SpawnMode] for the possible configurations. + </description> + </method> </methods> <members> <member name="allow_object_decoding" type="bool" setter="set_allow_object_decoding" getter="is_object_decoding_allowed" default="false"> @@ -94,6 +122,25 @@ Emitted when this MultiplayerAPI's [member network_peer] fails to establish a connection to a server. Only emitted on clients. </description> </signal> + <signal name="network_despawn"> + <argument index="0" name="id" type="int" /> + <argument index="1" name="scene_id" type="int" /> + <argument index="2" name="node" type="Node" /> + <argument index="3" name="data" type="PackedByteArray" /> + <description> + Emitted on a client before deleting a local Node upon receiving a despawn request from the server. + </description> + </signal> + <signal name="network_despawn_request"> + <argument index="0" name="id" type="int" /> + <argument index="1" name="scene_id" type="int" /> + <argument index="2" name="parent" type="Node" /> + <argument index="3" name="name" type="String" /> + <argument index="4" name="data" type="PackedByteArray" /> + <description> + Emitted when a network despawn request has been received from a client, or for a [PackedScene] that has been configured as [constant SPAWN_MODE_CUSTOM]. + </description> + </signal> <signal name="network_peer_connected"> <argument index="0" name="id" type="int" /> <description> @@ -113,6 +160,39 @@ Emitted when this MultiplayerAPI's [member network_peer] receive a [code]packet[/code] with custom data (see [method send_bytes]). ID is the peer ID of the peer that sent the packet. </description> </signal> + <signal name="network_spawn"> + <argument index="0" name="id" type="int" /> + <argument index="1" name="scene_id" type="int" /> + <argument index="2" name="node" type="Node" /> + <argument index="3" name="data" type="PackedByteArray" /> + <description> + Emitted on a client after a new Node is instantiated locally and added to the SceneTree upon receiving a spawn request from the server. + </description> + </signal> + <signal name="network_spawn_request"> + <argument index="0" name="id" type="int" /> + <argument index="1" name="scene_id" type="int" /> + <argument index="2" name="parent" type="Node" /> + <argument index="3" name="name" type="String" /> + <argument index="4" name="data" type="PackedByteArray" /> + <description> + Emitted when a network spawn request has been received from a client, or for a [PackedScene] that has been configured as [constant SPAWN_MODE_CUSTOM]. + </description> + </signal> + <signal name="network_spawnable_added"> + <argument index="0" name="scene_id" type="int" /> + <argument index="1" name="node" type="Node" /> + <description> + Emitted when an instance of a [PackedScene] that has been configured for networking enters the [SceneTree]. See [method spawnable_config]. + </description> + </signal> + <signal name="network_spawnable_removed"> + <argument index="0" name="scene_id" type="int" /> + <argument index="1" name="node" type="Node" /> + <description> + Emitted when an instance of a [PackedScene] that has been configured for networking leaves the [SceneTree]. See [method spawnable_config]. + </description> + </signal> <signal name="server_disconnected"> <description> Emitted when this MultiplayerAPI's [member network_peer] disconnects from server. Only emitted on clients. @@ -132,5 +212,14 @@ <constant name="RPC_MODE_PUPPET" value="3" enum="RPCMode"> Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on puppets for this node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or property changes from the node's network master, see [method Node.set_network_master]. </constant> + <constant name="SPAWN_MODE_NONE" value="0" enum="SpawnMode"> + Used with [method spawnable_config] to identify a [PackedScene] that should not be replicated. + </constant> + <constant name="SPAWN_MODE_SERVER" value="1" enum="SpawnMode"> + Used with [method spawnable_config] to identify a [PackedScene] that should be automatically replicated from server to clients. + </constant> + <constant name="SPAWN_MODE_CUSTOM" value="2" enum="SpawnMode"> + Used with [method spawnable_config] to identify a [PackedScene] that can be manually replicated among peers. + </constant> </constants> </class> diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index 983d8961fb..49901dc4d9 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -113,8 +113,9 @@ <argument index="0" name="target" type="Vector3" /> <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> <description> - Rotates itself so that the local -Z axis points towards the [code]target[/code] position. - The transform will first be rotated around the given [code]up[/code] vector, and then fully aligned to the target by a further rotation around an axis perpendicular to both the [code]target[/code] and [code]up[/code] vectors. + Rotates the node so that the local forward axis (-Z) points toward the [code]target[/code] position. + The local up axis (+Y) points as close to the [code]up[/code] vector as possible while staying perpendicular to the local forward axis. The resulting transform is orthogonal, and the scale is preserved. Non-uniform scaling may not work correctly. + The [code]target[/code] position cannot be the same as the node's position, the [code]up[/code] vector cannot be zero, and the direction from the node's position to the [code]target[/code] vector cannot be parallel to the [code]up[/code] vector. Operations take place in global space. </description> </method> @@ -124,7 +125,7 @@ <argument index="1" name="target" type="Vector3" /> <argument index="2" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> <description> - Moves the node to the specified [code]position[/code], and then rotates itself to point toward the [code]target[/code] as per [method look_at]. Operations take place in global space. + Moves the node to the specified [code]position[/code], and then rotates the node to point toward the [code]target[/code] as per [method look_at]. Operations take place in global space. </description> </method> <method name="orthonormalize"> diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml index ab3a04698f..4c6adfca32 100644 --- a/doc/classes/PhysicsDirectBodyState2D.xml +++ b/doc/classes/PhysicsDirectBodyState2D.xml @@ -137,6 +137,13 @@ Returns the current state of the space, useful for queries. </description> </method> + <method name="get_velocity_at_local_position" qualifiers="const"> + <return type="Vector2" /> + <argument index="0" name="local_position" type="Vector2" /> + <description> + Returns the body's velocity at the given relative position, including both translation and rotation. + </description> + </method> <method name="integrate_forces"> <return type="void" /> <description> diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml index 6af62c2bcc..271668e339 100644 --- a/doc/classes/PhysicsDirectBodyState3D.xml +++ b/doc/classes/PhysicsDirectBodyState3D.xml @@ -138,6 +138,13 @@ Returns the current state of the space, useful for queries. </description> </method> + <method name="get_velocity_at_local_position" qualifiers="const"> + <return type="Vector3" /> + <argument index="0" name="local_position" type="Vector3" /> + <description> + Returns the body's velocity at the given relative position, including both translation and rotation. + </description> + </method> <method name="integrate_forces"> <return type="void" /> <description> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 7bca8afdda..d6b7318a06 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -572,6 +572,8 @@ <argument index="3" name="infinite_inertia" type="bool" /> <argument index="4" name="margin" type="float" default="0.001" /> <argument index="5" name="result" type="PhysicsTestMotionResult3D" default="null" /> + <argument index="6" name="exclude_raycast_shapes" type="bool" default="true" /> + <argument index="7" name="exclude" type="Array" default="[]" /> <description> Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult3D] can be passed to return additional information in. </description> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 383049fb3e..6eba469e54 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -741,6 +741,34 @@ <member name="internationalization/locale/test" type="String" setter="" getter="" default=""""> If non-empty, this locale will be used when running the project from the editor. </member> + <member name="internationalization/pseudolocalization/double_vowels" type="bool" setter="" getter="" default="false"> + Double vowels in strings during pseudolocalization to simulate the lengthening of text due to localization. + </member> + <member name="internationalization/pseudolocalization/expansion_ratio" type="float" setter="" getter="" default="0.0"> + The expansion ratio to use during pseudolocalization. A value of [code]0.3[/code] is sufficient for most practical purposes, and will increase the length of each string by 30%. + </member> + <member name="internationalization/pseudolocalization/fake_bidi" type="bool" setter="" getter="" default="false"> + If [code]true[/code], emulate bidirectional (right-to-left) text when pseudolocalization is enabled. This can be used to spot issues with RTL layout and UI mirroring that will crop up if the project is localized to RTL languages such as Arabic or Hebrew. + </member> + <member name="internationalization/pseudolocalization/override" type="bool" setter="" getter="" default="false"> + Replace all characters in the string with [code]*[/code]. Useful for finding non-localizable strings. + </member> + <member name="internationalization/pseudolocalization/prefix" type="String" setter="" getter="" default=""[""> + Prefix that will be prepended to the pseudolocalized string. + </member> + <member name="internationalization/pseudolocalization/replace_with_accents" type="bool" setter="" getter="" default="true"> + Replace all characters with their accented variants during pseudolocalization. + </member> + <member name="internationalization/pseudolocalization/skip_placeholders" type="bool" setter="" getter="" default="true"> + Skip placeholders for string formatting like [code]%s[/code] or [code]%f[/code] during pseudolocalization. Useful to identify strings which need additional control characters to display correctly. + </member> + <member name="internationalization/pseudolocalization/suffix" type="String" setter="" getter="" default=""]""> + Suffix that will be appended to the pseudolocalized string. + </member> + <member name="internationalization/pseudolocalization/use_pseudolocalization" type="bool" setter="" getter="" default="false"> + If [code]true[/code], enables pseudolocalization for the project. This can be used to spot untranslatable strings or layout issues that may occur once the project is localized to languages that have longer strings than the source language. + [b]Note:[/b] This property is only read when the project starts. To toggle pseudolocalization at run-time, use [member TranslationServer.pseudolocalization_enabled] instead. + </member> <member name="internationalization/rendering/force_right_to_left_layout_direction" type="bool" setter="" getter="" default="false"> Force layout direction and text writing direction to RTL for all locales. </member> diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 1098af0eea..c329821646 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -1148,7 +1148,7 @@ </constant> <constant name="TEXTURE_USAGE_CAN_COPY_TO_BIT" value="256" enum="TextureUsageBits"> </constant> - <constant name="TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT" value="512" enum="TextureUsageBits"> + <constant name="TEXTURE_USAGE_INPUT_ATTACHMENT_BIT" value="512" enum="TextureUsageBits"> </constant> <constant name="TEXTURE_SWIZZLE_IDENTITY" value="0" enum="TextureSwizzle"> </constant> diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index 3a3ce189d5..81e825194b 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -34,6 +34,13 @@ Returns the list of recognized extensions for a resource type. </description> </method> + <method name="get_resource_uid"> + <return type="int" /> + <argument index="0" name="path" type="String" /> + <description> + Returns the ID associated with a given resource path, or [code]-1[/code] when no such ID exists. + </description> + </method> <method name="has_cached"> <return type="bool" /> <argument index="0" name="path" type="String" /> diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 538e93d505..7bbcc5e0b5 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -21,7 +21,7 @@ <argument index="1" name="width" type="int" default="0" /> <argument index="2" name="height" type="int" default="0" /> <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" /> - <argument index="4" name="inline_align" type="int" enum="VAlign" default="0" /> + <argument index="4" name="inline_align" type="int" enum="InlineAlign" default="5" /> <description> Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image and a [code]color[/code] to tint the image. If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio. @@ -288,7 +288,7 @@ <method name="push_table"> <return type="void" /> <argument index="0" name="columns" type="int" /> - <argument index="1" name="inline_align" type="int" enum="VAlign" default="0" /> + <argument index="1" name="inline_align" type="int" enum="InlineAlign" default="0" /> <description> Adds a [code][table=columns,inline_align][/code] tag to the tag stack. </description> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 027ae2000a..0376a3f96e 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -89,7 +89,7 @@ <return type="int" /> <argument index="0" name="to" type="String" /> <description> - Performs a case-sensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/code] of each string, which roughly matches the alphabetical order. + Performs a case-sensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [code]to[/code] string or [code]-1[/code] if the "base" string is shorter than the [code]to[/code] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters. [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [code]to[/code] string is empty or [code]0[/code] if both strings are empty. To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method naturalnocasecmp_to]. @@ -388,7 +388,7 @@ <return type="int" /> <argument index="0" name="to" type="String" /> <description> - Performs a case-insensitive [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/code] of each string, which roughly matches the alphabetical order. Internally, lowercase characters will be converted to uppercase during the comparison. + Performs a case-insensitive [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters will be converted to uppercase during the comparison. When used for sorting, natural order comparison will order suites of numbers as expected by most people. If you sort the numbers from 1 to 10 using natural order, you will get [code][1, 2, 3, ...][/code] instead of [code][1, 10, 2, 3, ...][/code]. [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [code]to[/code] string or [code]-1[/code] if the "base" string is shorter than the [code]to[/code] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters. [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [code]to[/code] string is empty or [code]0[/code] if both strings are empty. @@ -399,7 +399,7 @@ <return type="int" /> <argument index="0" name="to" type="String" /> <description> - Performs a case-insensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/code] of each string, which roughly matches the alphabetical order. Internally, lowercase characters will be converted to uppercase during the comparison. + Performs a case-insensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters will be converted to uppercase during the comparison. [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [code]to[/code] string or [code]-1[/code] if the "base" string is shorter than the [code]to[/code] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters. [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [code]to[/code] string is empty or [code]0[/code] if both strings are empty. To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to] and [method naturalnocasecmp_to]. diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml index cc66f56d65..daa7298418 100644 --- a/doc/classes/TextLine.xml +++ b/doc/classes/TextLine.xml @@ -13,7 +13,7 @@ <return type="bool" /> <argument index="0" name="key" type="Variant" /> <argument index="1" name="size" type="Vector2" /> - <argument index="2" name="inline_align" type="int" enum="VAlign" default="1" /> + <argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" /> <argument index="3" name="length" type="int" default="1" /> <description> Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters. @@ -122,7 +122,7 @@ <return type="bool" /> <argument index="0" name="key" type="Variant" /> <argument index="1" name="size" type="Vector2" /> - <argument index="2" name="inline_align" type="int" enum="VAlign" default="1" /> + <argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" /> <description> Sets new size and alignment of embedded object. </description> diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml index 9050f9246a..811fe32eb2 100644 --- a/doc/classes/TextParagraph.xml +++ b/doc/classes/TextParagraph.xml @@ -13,7 +13,7 @@ <return type="bool" /> <argument index="0" name="key" type="Variant" /> <argument index="1" name="size" type="Vector2" /> - <argument index="2" name="inline_align" type="int" enum="VAlign" default="1" /> + <argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" /> <argument index="3" name="length" type="int" default="1" /> <description> Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters. @@ -240,7 +240,7 @@ <return type="bool" /> <argument index="0" name="key" type="Variant" /> <argument index="1" name="size" type="Vector2" /> - <argument index="2" name="inline_align" type="int" enum="VAlign" default="1" /> + <argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" /> <description> Sets new size and alignment of embedded object. </description> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index dbf7ae93aa..ac56be4392 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -541,7 +541,7 @@ <argument index="0" name="shaped" type="RID" /> <argument index="1" name="key" type="Variant" /> <argument index="2" name="size" type="Vector2" /> - <argument index="3" name="inline_align" type="int" enum="VAlign" default="1" /> + <argument index="3" name="inline_align" type="int" enum="InlineAlign" default="5" /> <argument index="4" name="length" type="int" default="1" /> <description> Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters. @@ -817,7 +817,7 @@ <argument index="0" name="shaped" type="RID" /> <argument index="1" name="key" type="Variant" /> <argument index="2" name="size" type="Vector2" /> - <argument index="3" name="inline_align" type="int" enum="VAlign" default="1" /> + <argument index="3" name="inline_align" type="int" enum="InlineAlign" default="5" /> <description> Sets new size and alignment of embedded object. </description> diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml index 53cdfd53c9..1c906f6a51 100644 --- a/doc/classes/Transform3D.xml +++ b/doc/classes/Transform3D.xml @@ -79,9 +79,8 @@ <argument index="0" name="target" type="Vector3" /> <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" /> <description> - Returns a copy of the transform rotated such that its -Z axis points towards the [code]target[/code] position. - The transform will first be rotated around the given [code]up[/code] vector, and then fully aligned to the target by a further rotation around an axis perpendicular to both the [code]target[/code] and [code]up[/code] vectors. - Operations take place in global space. + Returns a copy of the transform rotated such that the forward axis (-Z) points towards the [code]target[/code] position. + The up axis (+Y) points as close to the [code]up[/code] vector as possible while staying perpendicular to the forward axis. The resulting transform is orthonormalized. The existing rotation, scale, and skew information from the original transform is discarded. The [code]target[/code] and [code]up[/code] vectors cannot be zero, cannot be parallel to each other, and are defined in global/parent space. </description> </method> <method name="operator !=" qualifiers="operator"> diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml index 655c16b0cd..029848be33 100644 --- a/doc/classes/TranslationServer.xml +++ b/doc/classes/TranslationServer.xml @@ -51,6 +51,19 @@ It will return a [code]nullptr[/code] if there is no [Translation] instance that matches the [code]locale[/code]. </description> </method> + <method name="pseudolocalize" qualifiers="const"> + <return type="StringName" /> + <argument index="0" name="message" type="StringName" /> + <description> + Returns the pseudolocalized string based on the [code]p_message[/code] passed in. + </description> + </method> + <method name="reload_pseudolocalization"> + <return type="void" /> + <description> + Reparses the pseudolocalization options and reloads the translation. + </description> + </method> <method name="remove_translation"> <return type="void" /> <argument index="0" name="translation" type="Translation" /> @@ -85,6 +98,11 @@ </description> </method> </methods> + <members> + <member name="pseudolocalization_enabled" type="bool" setter="set_pseudolocalization_enabled" getter="is_pseudolocalization_enabled" default="false"> + If [code]true[/code], enables the use of pseudolocalization. See [member ProjectSettings.internationalization/pseudolocalization/use_pseudolocalization] for details. + </member> + </members> <constants> </constants> </class> diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 9ee2a28240..b5bd6cef38 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -1804,6 +1804,10 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T image_create_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } + if (p_format.usage_bits & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) { + image_create_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } + if (p_format.usage_bits & TEXTURE_USAGE_CAN_UPDATE_BIT) { image_create_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; } @@ -2134,6 +2138,10 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID } } + if (texture.usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT) { + usage_info.usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + } + if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { usage_info.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; } @@ -3275,8 +3283,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF for (int i = 0; i < p_attachments.size(); i++) { ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); - ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), - VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set."); + ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)), + VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (color, depth, input or stencil) bit set."); VkAttachmentDescription description = {}; description.flags = 0; @@ -3473,7 +3481,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; } else { ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ")."); - ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as input attachment."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_INPUT_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it isn't marked as an input texture."); ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); reference.attachment = attachment; reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -3497,12 +3505,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } else { ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ")."); ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused."); - ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as resolve attachment."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment, it isn't marked as a color texture."); ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1; ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample."); reference.attachment = attachment; - reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; attachment_last_pass[attachment] = i; } resolve_references.push_back(reference); @@ -3632,8 +3640,10 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF render_pass_create_info.pDependencies = nullptr; } + // These are only used if we use multiview but we need to define them in scope. const uint32_t view_mask = (1 << p_view_count) - 1; const uint32_t correlation_mask = (1 << p_view_count) - 1; + Vector<uint32_t> view_masks; VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info; if (p_view_count > 1) { @@ -3645,10 +3655,15 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF // Make sure we limit this to the number of views we support. ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass"); + // Set view masks for each subpass + for (uint32_t i = 0; i < subpasses.size(); i++) { + view_masks.push_back(view_mask); + }; + render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; render_pass_multiview_create_info.pNext = nullptr; - render_pass_multiview_create_info.subpassCount = 1; - render_pass_multiview_create_info.pViewMasks = &view_mask; + render_pass_multiview_create_info.subpassCount = subpasses.size(); + render_pass_multiview_create_info.pViewMasks = view_masks.ptr(); render_pass_multiview_create_info.dependencyCount = 0; render_pass_multiview_create_info.pViewOffsets = nullptr; render_pass_multiview_create_info.correlationMaskCount = 1; @@ -4506,6 +4521,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve } break; case SPV_REFLECT_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { info.type = UNIFORM_TYPE_INPUT_ATTACHMENT; + need_array_dimensions = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: { ERR_PRINT("Acceleration structure not supported."); @@ -5490,7 +5506,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.sampler = *sampler; img_info.imageView = texture->view; - if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { + if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) { UniformSet::AttachableTexture attachable_texture; attachable_texture.bind = set_uniform.binding; attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j + 1]; @@ -5543,7 +5559,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, img_info.sampler = VK_NULL_HANDLE; img_info.imageView = texture->view; - if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)) { + if (texture->usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_INPUT_ATTACHMENT_BIT)) { UniformSet::AttachableTexture attachable_texture; attachable_texture.bind = set_uniform.binding; attachable_texture.texture = texture->owner.is_valid() ? texture->owner : uniform.ids[j]; @@ -7416,6 +7432,10 @@ void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } +uint32_t RenderingDeviceVulkan::draw_list_get_current_pass() { + return draw_list_current_subpass; +} + RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass() { ERR_FAIL_COND_V(draw_list == nullptr, INVALID_ID); ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index f9ff61310a..dc4583d837 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -1149,6 +1149,7 @@ public: virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect); virtual void draw_list_disable_scissor(DrawListID p_list); + virtual uint32_t draw_list_get_current_pass(); virtual DrawListID draw_list_switch_to_next_pass(); virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids); diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index f504bad60d..775c999b15 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -35,6 +35,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" +#include <share.h> // _SH_DENYNO #include <shlwapi.h> #include <windows.h> @@ -77,8 +78,8 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { return ERR_INVALID_PARAMETER; } - /* pretty much every implementation that uses fopen as primary - backend supports utf8 encoding */ + /* Pretty much every implementation that uses fopen as primary + backend supports utf8 encoding. */ struct _stat st; if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) { @@ -113,10 +114,10 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { path = path + ".tmp"; } - errno_t errcode = _wfopen_s(&f, (LPCWSTR)(path.utf16().get_data()), mode_string); + f = _wfsopen((LPCWSTR)(path.utf16().get_data()), mode_string, _SH_DENYNO); if (f == nullptr) { - switch (errcode) { + switch (errno) { case ENOENT: { last_error = ERR_FILE_NOT_FOUND; } break; @@ -157,10 +158,10 @@ void FileAccessWindows::close() { #else if (!PathFileExistsW((LPCWSTR)(save_path.utf16().get_data()))) { #endif - //creating new file + // Creating new file rename_error = _wrename((LPCWSTR)((save_path + ".tmp").utf16().get_data()), (LPCWSTR)(save_path.utf16().get_data())) != 0; } else { - //atomic replace for existing file + // Atomic replace for existing file rename_error = !ReplaceFileW((LPCWSTR)(save_path.utf16().get_data()), (LPCWSTR)((save_path + ".tmp").utf16().get_data()), nullptr, 2 | 4, nullptr, nullptr); } if (rename_error) { @@ -205,6 +206,7 @@ void FileAccessWindows::seek(uint64_t p_position) { void FileAccessWindows::seek_end(int64_t p_position) { ERR_FAIL_COND(!f); + if (_fseeki64(f, p_position, SEEK_END)) { check_errors(); } @@ -237,6 +239,7 @@ bool FileAccessWindows::eof_reached() const { uint8_t FileAccessWindows::get_8() const { ERR_FAIL_COND_V(!f, 0); + if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == WRITE) { fflush(f); @@ -273,6 +276,7 @@ Error FileAccessWindows::get_error() const { void FileAccessWindows::flush() { ERR_FAIL_COND(!f); + fflush(f); if (prev_op == WRITE) { prev_op = 0; @@ -281,6 +285,7 @@ void FileAccessWindows::flush() { void FileAccessWindows::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); + if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == READ) { if (last_error != ERR_FILE_EOF) { @@ -295,6 +300,7 @@ void FileAccessWindows::store_8(uint8_t p_dest) { void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND(!f); ERR_FAIL_COND(!p_src && p_length > 0); + if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == READ) { if (last_error != ERR_FILE_EOF) { @@ -307,10 +313,8 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { } bool FileAccessWindows::file_exists(const String &p_name) { - FILE *g; - //printf("opening file %s\n", p_fname.utf8().get_data()); String filename = fix_path(p_name); - _wfopen_s(&g, (LPCWSTR)(filename.utf16().get_data()), L"rb"); + FILE *g = _wfsopen((LPCWSTR)(filename.utf16().get_data()), L"rb", _SH_DENYNO); if (g == nullptr) { return false; } else { diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index c9d3df9ce2..f40dc3c64a 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -3418,6 +3418,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) { //potential new key, does not exist if (num_tracks == 1) { + // TRANSLATORS: %s will be replaced by a phrase describing the target of track. insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), p_id.query)); } else { insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?"), num_tracks)); @@ -3525,7 +3526,8 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ id.track_idx = track_idx; id.value = p_xform; id.type = Animation::TYPE_TRANSFORM3D; - id.query = "node '" + p_node->get_name() + "'"; + // TRANSLATORS: This describes the target of new animation track, will be inserted into another string. + id.query = vformat(TTR("node '%s'"), p_node->get_name()); id.advance = false; //dialog insert @@ -3547,7 +3549,8 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant id.track_idx = i; id.value = p_value; id.type = Animation::TYPE_ANIMATION; - id.query = "animation"; + // TRANSLATORS: This describes the target of new animation track, will be inserted into another string. + id.query = TTR("animation"); id.advance = false; //dialog insert _query_insert(id); @@ -3560,7 +3563,7 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant id.track_idx = -1; id.value = p_value; id.type = Animation::TYPE_ANIMATION; - id.query = "animation"; + id.query = TTR("animation"); id.advance = false; //dialog insert _query_insert(id); @@ -3609,7 +3612,8 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p id.track_idx = i; id.value = p_value; id.type = Animation::TYPE_VALUE; - id.query = "property '" + p_property + "'"; + // TRANSLATORS: This describes the target of new animation track, will be inserted into another string. + id.query = vformat(TTR("property '%s'"), p_property); id.advance = false; //dialog insert _query_insert(id); @@ -3639,7 +3643,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p id.track_idx = i; id.value = value; id.type = Animation::TYPE_BEZIER; - id.query = "property '" + p_property + "'"; + id.query = vformat(TTR("property '%s'"), p_property); id.advance = false; //dialog insert _query_insert(id); @@ -3655,7 +3659,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p id.track_idx = -1; id.value = p_value; id.type = Animation::TYPE_VALUE; - id.query = "property '" + p_property + "'"; + id.query = vformat(TTR("property '%s'"), p_property); id.advance = false; //dialog insert _query_insert(id); @@ -3708,7 +3712,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari id.track_idx = i; id.value = p_value; id.type = Animation::TYPE_VALUE; - id.query = "property '" + p_property + "'"; + id.query = vformat(TTR("property '%s'"), p_property); id.advance = p_advance; //dialog insert _query_insert(id); @@ -3733,7 +3737,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari id.track_idx = i; id.value = value; id.type = Animation::TYPE_BEZIER; - id.query = "property '" + p_property + "'"; + id.query = vformat(TTR("property '%s'"), p_property); id.advance = p_advance; //dialog insert _query_insert(id); @@ -3747,7 +3751,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari id.track_idx = -1; id.value = p_value; id.type = Animation::TYPE_VALUE; - id.query = "property '" + p_property + "'"; + id.query = vformat(TTR("property '%s'"), p_property); id.advance = p_advance; //dialog insert _query_insert(id); diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 72a0c353e8..84a9237a96 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -563,7 +563,7 @@ void EditorFeatureProfileManager::_class_list_item_selected() { int feature_id = md; String feature_description = EditorFeatureProfile::get_feature_description(EditorFeatureProfile::Feature(feature_id)); - description_bit->set_text(feature_description); + description_bit->set_text(TTRGET(feature_description)); return; } else { return; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index d7b7e8e52d..679f2e8ce4 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1907,8 +1907,7 @@ void EditorInspector::update_tree() { } Vector<String> slices = propname.operator String().split("/"); - if (slices.size() == 2 && slices[0].begins_with("custom_")) { - // Likely a theme property. + if (slices.size() == 2 && slices[0].begins_with("theme_override_")) { for (int i = 0; i < F->get().theme_properties.size(); i++) { if (F->get().theme_properties[i].name == slices[1]) { descr = DTR(F->get().theme_properties[i].description); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 20710b192c..2126a7b8be 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -736,11 +736,26 @@ void EditorNode::_notification(int p_what) { void EditorNode::_update_update_spinner() { update_spinner->set_visible(EditorSettings::get_singleton()->get("interface/editor/show_update_spinner")); - bool update_continuously = EditorSettings::get_singleton()->get("interface/editor/update_continuously"); + const bool update_continuously = EditorSettings::get_singleton()->get("interface/editor/update_continuously"); PopupMenu *update_popup = update_spinner->get_popup(); update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_CONTINUOUSLY), update_continuously); update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously); + if (update_continuously) { + update_spinner->set_tooltip(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it.")); + + // Use a different color for the update spinner when Update Continuously is enabled, + // as this feature should only be enabled for troubleshooting purposes. + // Make the icon modulate color overbright because icons are not completely white on a dark theme. + // On a light theme, icons are dark, so we need to modulate them with an even brighter color. + const bool dark_theme = EditorSettings::get_singleton()->is_dark_theme(); + update_spinner->set_self_modulate( + gui_base->get_theme_color("error_color", "Editor") * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25))); + } else { + update_spinner->set_tooltip(TTR("Spins when the editor window redraws.")); + update_spinner->set_self_modulate(Color(1, 1, 1)); + } + OS::get_singleton()->set_low_processor_usage_mode(!update_continuously); } @@ -4929,6 +4944,16 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) { scene_tabs_context_menu->set_position(mb->get_global_position()); scene_tabs_context_menu->popup(); } + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) { + int previous_tab = editor_data.get_edited_scene() - 1; + previous_tab = previous_tab >= 0 ? previous_tab : editor_data.get_edited_scene_count() - 1; + _scene_tab_changed(previous_tab); + } + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) { + int next_tab = editor_data.get_edited_scene() + 1; + next_tab %= editor_data.get_edited_scene_count(); + _scene_tab_changed(next_tab); + } } } @@ -6511,7 +6536,6 @@ EditorNode::EditorNode() { layout_dialog->connect("name_confirmed", callable_mp(this, &EditorNode::_dialog_action)); update_spinner = memnew(MenuButton); - update_spinner->set_tooltip(TTR("Spins when the editor window redraws.")); right_menu_hb->add_child(update_spinner); update_spinner->set_icon(gui_base->get_theme_icon(SNAME("Progress1"), SNAME("EditorIcons"))); update_spinner->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index fa03d281f2..789cabea9a 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2854,6 +2854,10 @@ void EditorPropertyResource::setup(Object *p_object, const String &p_path, const EditorScriptPicker *script_picker = memnew(EditorScriptPicker); script_picker->set_script_owner(Object::cast_to<Node>(p_object)); resource_picker = script_picker; + } else if (p_path == "shader" && p_base_type == "Shader" && Object::cast_to<ShaderMaterial>(p_object)) { + EditorShaderPicker *shader_picker = memnew(EditorShaderPicker); + shader_picker->set_edited_material(Object::cast_to<ShaderMaterial>(p_object)); + resource_picker = shader_picker; } else { resource_picker = memnew(EditorResourcePicker); } diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index f3965fe7de..a4ab749db4 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -847,6 +847,8 @@ EditorResourcePicker::EditorResourcePicker() { edit_button->connect("gui_input", callable_mp(this, &EditorResourcePicker::_button_input)); } +// EditorScriptPicker + void EditorScriptPicker::set_create_options(Object *p_menu_node) { PopupMenu *menu_node = Object::cast_to<PopupMenu>(p_menu_node); if (!menu_node) { @@ -895,3 +897,42 @@ void EditorScriptPicker::_bind_methods() { EditorScriptPicker::EditorScriptPicker() { } + +// EditorShaderPicker + +void EditorShaderPicker::set_create_options(Object *p_menu_node) { + PopupMenu *menu_node = Object::cast_to<PopupMenu>(p_menu_node); + if (!menu_node) { + return; + } + + menu_node->add_icon_item(get_theme_icon("Shader", "EditorIcons"), TTR("New Shader"), OBJ_MENU_NEW_SHADER); + menu_node->add_separator(); +} + +bool EditorShaderPicker::handle_menu_selected(int p_which) { + Ref<ShaderMaterial> material = Ref<ShaderMaterial>(get_edited_material()); + + switch (p_which) { + case OBJ_MENU_NEW_SHADER: { + if (material.is_valid()) { + EditorNode::get_singleton()->get_scene_tree_dock()->open_shader_dialog(material); + return true; + } + } break; + default: + break; + } + return false; +} + +void EditorShaderPicker::set_edited_material(ShaderMaterial *p_material) { + edited_material = p_material; +} + +ShaderMaterial *EditorShaderPicker::get_edited_material() const { + return edited_material; +} + +EditorShaderPicker::EditorShaderPicker() { +} diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h index a4c3006c02..d77c31f831 100644 --- a/editor/editor_resource_picker.h +++ b/editor/editor_resource_picker.h @@ -144,4 +144,23 @@ public: EditorScriptPicker(); }; +class EditorShaderPicker : public EditorResourcePicker { + GDCLASS(EditorShaderPicker, EditorResourcePicker); + + enum ExtraMenuOption { + OBJ_MENU_NEW_SHADER = 10, + }; + + ShaderMaterial *edited_material = nullptr; + +public: + virtual void set_create_options(Object *p_menu_node) override; + virtual bool handle_menu_selected(int p_which) override; + + void set_edited_material(ShaderMaterial *p_material); + ShaderMaterial *get_edited_material() const; + + EditorShaderPicker(); +}; + #endif // EDITOR_RESOURCE_PICKER_H diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 29ac836834..b1cd53092d 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -374,6 +374,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/display_scale", 0); // Display what the Auto display scale setting effectively corresponds to. float scale = get_auto_display_scale(); + + _initial_set("interface/editor/enable_debugging_pseudolocalization", false); + set_restart_if_changed("interface/editor/enable_debugging_pseudolocalization", true); + // Use pseudolocalization in editor. + hints["interface/editor/display_scale"] = PropertyInfo(Variant::INT, "interface/editor/display_scale", PROPERTY_HINT_ENUM, vformat("Auto (%d%%),75%%,100%%,125%%,150%%,175%%,200%%,Custom", Math::round(scale * 100)), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/custom_display_scale", 1.0f); hints["interface/editor/custom_display_scale"] = PropertyInfo(Variant::FLOAT, "interface/editor/custom_display_scale", PROPERTY_HINT_RANGE, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); @@ -953,11 +958,11 @@ fail: } void EditorSettings::setup_language() { + TranslationServer::get_singleton()->set_editor_pseudolocalization(get("interface/editor/enable_debugging_pseudolocalization")); String lang = get("interface/editor/editor_language"); if (lang == "en") { return; // Default, nothing to do. } - // Load editor translation for configured/detected locale. EditorTranslationList *etl = _editor_translations; while (etl->data) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0d714065e3..08dd37bc73 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1345,7 +1345,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("folder_icon_modulate", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25)).lerp(accent_color, 0.7)); theme->set_color("files_disabled", "FileDialog", font_disabled_color); - // color picker + // ColorPicker theme->set_constant("margin", "ColorPicker", popup_margin_size); theme->set_constant("sv_width", "ColorPicker", 256 * EDSCALE); theme->set_constant("sv_height", "ColorPicker", 256 * EDSCALE); @@ -1358,6 +1358,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("bar_arrow", "ColorPicker", theme->get_icon("ColorPickerBarArrow", "EditorIcons")); theme->set_icon("picker_cursor", "ColorPicker", theme->get_icon("PickerCursor", "EditorIcons")); + // ColorPickerButton theme->set_icon("bg", "ColorPickerButton", theme->get_icon("GuiMiniCheckerboard", "EditorIcons")); // Information on 3D viewport diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 699957897f..b646b3361d 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -889,8 +889,8 @@ ExportTemplateManager::ExportTemplateManager() { request_mirrors->connect("request_completed", callable_mp(this, &ExportTemplateManager::_refresh_mirrors_completed)); mirror_options_button = memnew(MenuButton); - mirror_options_button->get_popup()->add_item("Open in Web Browser", VISIT_WEB_MIRROR); - mirror_options_button->get_popup()->add_item("Copy Mirror URL", COPY_MIRROR_URL); + mirror_options_button->get_popup()->add_item(TTR("Open in Web Browser"), VISIT_WEB_MIRROR); + mirror_options_button->get_popup()->add_item(TTR("Copy Mirror URL"), COPY_MIRROR_URL); download_install_hb->add_child(mirror_options_button); mirror_options_button->get_popup()->connect("id_pressed", callable_mp(this, &ExportTemplateManager::_mirror_options_button_cbk)); diff --git a/editor/icons/PrismMesh.svg b/editor/icons/PrismMesh.svg index cca52bb7b0..0fd169cc8c 100644 --- a/editor/icons/PrismMesh.svg +++ b/editor/icons/PrismMesh.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.9824 1.002a1.0001 1.0001 0 0 0 -.81445.44336l-5.9727 8.9609-.027344.03906a1 1 0 0 0 -.0625.10742 1 1 0 0 0 .44727 1.3418l6 3a1.0001 1.0001 0 0 0 .89453 0l6-3a1 1 0 0 0 .44726-1.3418 1 1 0 0 0 -.0625-.10742l-6-9a1.0001 1.0001 0 0 0 -.84961-.44336zm-.98242 4.3008v7.0801l-3.5391-1.7715zm2 0 3.5391 5.3086-3.5391 1.7715z" fill="#ffca5f"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.9168678 1.8860265c-.3598509 1.0771598-1.9743383 5.9072035-2.95075512 8.8641335-.15505871.56144.26297692 1.081021.77506042 1.256186 1.9729807.978051 3.9341568 1.98391 5.9144721 2.944682.5872542.201411 1.0933197-.27019 1.6046594-.478049 1.7521944-.878995 3.5092364-1.748814 5.2583944-2.633556.53543-.305954.598247-1.041459.264856-1.51829-.991782-1.9723689-1.966021-3.9544106-2.968743-5.9207481-.320568-.4259931-.882722-.5397422-1.322158-.8066387-1.7413894-.8632626-4.7187151-2.3492561-5.2199521-2.59935915-.501237-.2501031-.9959833-.18552039-1.3558341.89163945zm1.6236276 1.4766588 4.2114703 2.1046892-2.3703904 7.1132625-4.2114703-2.104688zm5.6257546 4.2135626 1.479141 2.9582811-2.9603737 1.481232z" fill="#ffca5f"/></svg> diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index b615c73422..54b93edcdd 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -1414,7 +1414,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones //animation->set_loop(true); //create animation tracks - Vector<float> base_snapshots; + Vector<real_t> base_snapshots; float f = 0; float snapshot_interval = 1.0 / bake_fps; //should be customizable somewhere... @@ -1466,7 +1466,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones animation->track_set_path(track, path); animation->track_set_imported(track, true); //helps merging later - Vector<float> snapshots = base_snapshots; + Vector<real_t> snapshots = base_snapshots; if (nm.anim_tracks.size() == 1) { //use snapshot keys from anim track instead, because this was most likely exported baked diff --git a/editor/import/editor_importer_bake_reset.cpp b/editor/import/editor_importer_bake_reset.cpp index 541eab4f40..00dce6850e 100644 --- a/editor/import/editor_importer_bake_reset.cpp +++ b/editor/import/editor_importer_bake_reset.cpp @@ -30,6 +30,7 @@ #include "editor/import/editor_importer_bake_reset.h" +#include "core/error/error_list.h" #include "core/error/error_macros.h" #include "core/math/transform_3d.h" #include "editor/import/scene_importer_mesh_node_3d.h" @@ -158,8 +159,13 @@ void BakeReset::_fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, Ba p_ap->get_animation_list(&anim_names); Node *root = p_ap->get_owner(); ERR_FAIL_NULL(root); + if (!p_ap->has_animation(p_bake_anim)) { + return; + } Ref<Animation> a = p_ap->get_animation(p_bake_anim); - ERR_FAIL_NULL(a); + if (a.is_null()) { + return; + } for (int32_t track = 0; track < a->get_track_count(); track++) { NodePath path = a->track_get_path(track); String string_path = path; @@ -173,7 +179,10 @@ void BakeReset::_fetch_reset_animation(AnimationPlayer *p_ap, Map<StringName, Ba Quaternion rot; Vector3 scale; Error err = a->transform_track_get_key(track, key_i, &loc, &rot, &scale); - ERR_CONTINUE(err); + if (err != OK) { + ERR_PRINT_ONCE("Reset animation baker can't get key."); + continue; + } rot.normalize(); Basis rot_basis = Basis(rot, scale); BakeResetRestBone rest_bone; diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h index 24c950fdee..fe98a91ab3 100644 --- a/editor/plugins/animation_blend_space_1d_editor.h +++ b/editor/plugins/animation_blend_space_1d_editor.h @@ -92,7 +92,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin { PopupMenu *animations_menu; Vector<String> animations_to_add; float add_point_pos; - Vector<float> points; + Vector<real_t> points; bool dragging_selected_attempt; bool dragging_selected; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index c440064898..7fe12089c8 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -4073,7 +4073,7 @@ void CanvasItemEditor::_popup_warning_depop(Control *p_control) { info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10); } -void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const float p_duration) { +void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const double p_duration) { Timer *timer; if (!popup_temporarily_timers.has(p_control)) { timer = memnew(Timer); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 1f59dfbc49..495cd5f515 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -56,7 +56,7 @@ public: Transform2D pre_drag_xform; Rect2 pre_drag_rect; - List<float> pre_drag_bones_length; + List<real_t> pre_drag_bones_length; List<Dictionary> pre_drag_bones_undo_state; Dictionary undo_state; @@ -540,7 +540,7 @@ private: VSplitContainer *bottom_split; void _update_context_menu_stylebox(); - void _popup_warning_temporarily(Control *p_control, const float p_duration); + void _popup_warning_temporarily(Control *p_control, const double p_duration); void _popup_warning_depop(Control *p_control); void _set_owner_for_node_and_children(Node *p_node, Node *p_owner); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index d7618b973e..d47bd2d410 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -386,7 +386,7 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { Vector<Vector3> vertices; Vector<Vector3> normals; Vector<Vector2> uvs; - Vector<float> tangents; + Vector<real_t> tangents; Basis tt = Basis(Vector3(0, 1, 0), Math_PI * 0.5); for (int i = 1; i <= lats; i++) { @@ -635,7 +635,7 @@ Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Ref<AudioStreamPlayback> playback = stream->instance_playback(); ERR_FAIL_COND_V(playback.is_null(), Ref<Texture2D>()); - float len_s = stream->get_length(); + real_t len_s = stream->get_length(); if (len_s == 0) { len_s = 60; //one minute audio if no length specified } @@ -649,8 +649,8 @@ Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const playback->stop(); for (int i = 0; i < w; i++) { - float max = -1000; - float min = 1000; + real_t max = -1000; + real_t min = 1000; int from = uint64_t(i) * frame_length / w; int to = (uint64_t(i) + 1) * frame_length / w; to = MIN(to, frame_length); diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 5184e837ce..efec5a709d 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -60,7 +60,7 @@ void GPUParticles2DEditorPlugin::_file_selected(const String &p_file) { void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) { switch (p_idx) { case MENU_GENERATE_VISIBILITY_RECT: { - float gen_time = particles->get_lifetime(); + double gen_time = particles->get_lifetime(); if (gen_time < 1.0) { generate_seconds->set_value(1.0); } else { @@ -100,7 +100,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) { } void GPUParticles2DEditorPlugin::_generate_visibility_rect() { - float time = generate_seconds->get_value(); + double time = generate_seconds->get_value(); float running = 0.0; diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 8576082597..fff25b6f59 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -282,9 +282,9 @@ void GPUParticles3DEditor::_menu_option(int p_option) { } void GPUParticles3DEditor::_generate_aabb() { - float time = generate_seconds->get_value(); + double time = generate_seconds->get_value(); - float running = 0.0; + double running = 0.0; EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 46e15d97bf..b8cbaaf7c1 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -145,7 +145,7 @@ Variant EditorNode3DGizmo::get_handle_value(int p_id) const { return gizmo_plugin->get_handle_value(this, p_id); } -void EditorNode3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void EditorNode3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) { if (get_script_instance() && get_script_instance()->has_method("_set_handle")) { get_script_instance()->call("_set_handle", p_id, p_camera, p_point); return; @@ -155,7 +155,7 @@ void EditorNode3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p gizmo_plugin->set_handle(this, p_id, p_camera, p_point); } -void EditorNode3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cancel) const { +void EditorNode3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cancel) { if (get_script_instance() && get_script_instance()->has_method("_commit_handle")) { get_script_instance()->call("_commit_handle", p_id, p_restore, p_cancel); return; @@ -196,7 +196,7 @@ Transform3D EditorNode3DGizmo::get_subgizmo_transform(int p_id) const { return gizmo_plugin->get_subgizmo_transform(this, p_id); } -void EditorNode3DGizmo::set_subgizmo_transform(int p_id, Transform3D p_transform) const { +void EditorNode3DGizmo::set_subgizmo_transform(int p_id, Transform3D p_transform) { if (get_script_instance() && get_script_instance()->has_method("_set_subgizmo_transform")) { get_script_instance()->call("_set_subgizmo_transform", p_id, p_transform); return; @@ -206,7 +206,7 @@ void EditorNode3DGizmo::set_subgizmo_transform(int p_id, Transform3D p_transform gizmo_plugin->set_subgizmo_transform(this, p_id, p_transform); } -void EditorNode3DGizmo::commit_subgizmos(const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) const { +void EditorNode3DGizmo::commit_subgizmos(const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) { if (get_script_instance() && get_script_instance()->has_method("_commit_subgizmos")) { Array ids; for (int i = 0; i < p_ids.size(); i++) { @@ -1145,13 +1145,13 @@ Variant EditorNode3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_giz return Variant(); } -void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void EditorNode3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { if (get_script_instance() && get_script_instance()->has_method("_set_handle")) { get_script_instance()->call("_set_handle", p_gizmo, p_id, p_camera, p_point); } } -void EditorNode3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void EditorNode3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { if (get_script_instance() && get_script_instance()->has_method("_commit_handle")) { get_script_instance()->call("_commit_handle", p_gizmo, p_id, p_restore, p_cancel); } @@ -1184,13 +1184,13 @@ Transform3D EditorNode3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGi return Transform3D(); } -void EditorNode3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) const { +void EditorNode3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) { if (get_script_instance() && get_script_instance()->has_method("_set_subgizmo_transform")) { get_script_instance()->call("_set_subgizmo_transform", p_id, p_transform); } } -void EditorNode3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) const { +void EditorNode3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) { if (get_script_instance() && get_script_instance()->has_method("_commit_subgizmos")) { Array ids; for (int i = 0; i < p_ids.size(); i++) { @@ -1310,7 +1310,7 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec return Math::rad2deg(a); } -void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node()); Transform3D gt = light->get_global_transform(); Transform3D gi = gt.affine_inverse(); @@ -1354,7 +1354,7 @@ void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, } } -void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node()); if (p_cancel) { light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore); @@ -1538,7 +1538,7 @@ Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo return player->get_emission_angle(); } -void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); Transform3D gt = player->get_global_transform(); @@ -1575,7 +1575,7 @@ void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo } } -void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); if (p_cancel) { @@ -1684,7 +1684,7 @@ Variant Camera3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, } } -void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node()); Transform3D gt = camera->get_global_transform(); @@ -1713,7 +1713,7 @@ void Camera3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, } } -void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { @@ -2572,7 +2572,7 @@ Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo return Variant(soft_body->is_point_pinned(p_id)); } -void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node()); soft_body->pin_point_toggle(p_id); } @@ -2628,7 +2628,7 @@ Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3 return notifier->get_aabb(); } -void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node()); Transform3D gt = notifier->get_global_transform(); @@ -2680,7 +2680,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p } } -void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node()); if (p_cancel) { @@ -2820,7 +2820,7 @@ Variant GPUParticles3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_g return particles->get_visibility_aabb(); } -void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node()); Transform3D gt = particles->get_global_transform(); @@ -2871,7 +2871,7 @@ void GPUParticles3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int } } -void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node()); if (p_cancel) { @@ -2985,7 +2985,7 @@ Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DG return Variant(); } -void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { Node3D *sn = p_gizmo->get_spatial_node(); Transform3D gt = sn->get_global_transform(); @@ -3031,7 +3031,7 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g } } -void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { Node3D *sn = p_gizmo->get_spatial_node(); if (Object::cast_to<GPUParticlesCollisionSphere>(sn) || Object::cast_to<GPUParticlesAttractorSphere>(sn)) { @@ -3245,7 +3245,7 @@ Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_ return AABB(probe->get_extents(), probe->get_origin_offset()); } -void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); Transform3D gt = probe->get_global_transform(); @@ -3302,7 +3302,7 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in } } -void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); AABB restore = p_restore; @@ -3424,7 +3424,7 @@ Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int return decal->get_extents(); } -void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node()); Transform3D gt = decal->get_global_transform(); @@ -3455,7 +3455,7 @@ void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Ca decal->set_extents(extents); } -void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node()); Vector3 restore = p_restore; @@ -3564,7 +3564,7 @@ Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, i return probe->get_extents(); } -void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node()); Transform3D gt = probe->get_global_transform(); @@ -3595,7 +3595,7 @@ void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, probe->set_extents(extents); } -void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node()); Vector3 restore = p_restore; @@ -3723,10 +3723,10 @@ Variant LightmapGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo return Variant(); } -void LightmapGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void LightmapGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { } -void LightmapGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void LightmapGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { } bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { @@ -3905,10 +3905,10 @@ Variant LightmapProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gi return Variant(); } -void LightmapProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void LightmapProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { } -void LightmapProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void LightmapProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { } bool LightmapProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { @@ -4124,7 +4124,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p return Variant(); } -void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node()); Ref<Shape3D> s = cs->get_shape(); @@ -4241,7 +4241,7 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i } } -void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(p_gizmo->get_spatial_node()); Ref<Shape3D> s = cs->get_shape(); diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index f303a61607..64f46f2b1a 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -63,7 +63,7 @@ class EditorNode3DGizmo : public Node3DGizmo { Vector<Vector3> secondary_handles; Vector<int> secondary_handle_ids; - float selectable_icon_size; + real_t selectable_icon_size; bool billboard_handle; bool valid; @@ -91,14 +91,14 @@ public: virtual bool is_handle_highlighted(int p_id) const; virtual String get_handle_name(int p_id) const; virtual Variant get_handle_value(int p_id) const; - virtual void set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) const; - virtual void commit_handle(int p_id, const Variant &p_restore, bool p_cancel = false) const; + virtual void set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point); + virtual void commit_handle(int p_id, const Variant &p_restore, bool p_cancel = false); virtual int subgizmos_intersect_ray(Camera3D *p_camera, const Vector2 &p_point) const; virtual Vector<int> subgizmos_intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum) const; virtual Transform3D get_subgizmo_transform(int p_id) const; - virtual void set_subgizmo_transform(int p_id, Transform3D p_transform) const; - virtual void commit_subgizmos(const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false) const; + virtual void set_subgizmo_transform(int p_id, Transform3D p_transform); + virtual void commit_subgizmos(const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false); void set_selected(bool p_selected) { selected = p_selected; } bool is_selected() const { return selected; } @@ -161,14 +161,14 @@ public: virtual bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const; virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const; virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const; - virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const; - virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const; + virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point); + virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false); virtual int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const; virtual Vector<int> subgizmos_intersect_frustum(const EditorNode3DGizmo *p_gizmo, const Camera3D *p_camera, const Vector<Plane> &p_frustum) const; virtual Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const; - virtual void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) const; - virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false) const; + virtual void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform); + virtual void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel = false); Ref<EditorNode3DGizmo> get_gizmo(Node3D *p_spatial); void set_state(int p_state); @@ -189,8 +189,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; void redraw(EditorNode3DGizmo *p_gizmo) override; Light3DGizmoPlugin(); @@ -206,8 +206,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; void redraw(EditorNode3DGizmo *p_gizmo) override; AudioStreamPlayer3DGizmoPlugin(); @@ -223,8 +223,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; void redraw(EditorNode3DGizmo *p_gizmo) override; Camera3DGizmoPlugin(); @@ -355,7 +355,7 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id) const override; SoftBody3DGizmoPlugin(); @@ -372,8 +372,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; VisibleOnScreenNotifier3DGizmoPlugin(); }; @@ -402,8 +402,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; GPUParticles3DGizmoPlugin(); }; @@ -419,8 +419,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; GPUParticlesCollision3DGizmoPlugin(); }; @@ -436,8 +436,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; ReflectionProbeGizmoPlugin(); }; @@ -453,8 +453,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; DecalGizmoPlugin(); }; @@ -470,8 +470,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; VoxelGIGizmoPlugin(); }; @@ -487,8 +487,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; LightmapGIGizmoPlugin(); }; @@ -504,8 +504,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; LightmapProbeGizmoPlugin(); }; @@ -533,8 +533,8 @@ public: String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) const override; + void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel = false) override; CollisionShape3DGizmoPlugin(); }; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index 5ed8205475..4cb11cc5f1 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -122,31 +122,28 @@ void ViewportRotationControl::_draw() { } void ViewportRotationControl::_draw_axis(const Axis2D &p_axis) { - bool focused = focused_axis == p_axis.axis; - bool positive = p_axis.axis < 3; - bool front = (Math::abs(p_axis.z_axis) <= 0.001 && positive) || p_axis.z_axis > 0.001; - int direction = p_axis.axis % 3; + const bool focused = focused_axis == p_axis.axis; + const bool positive = p_axis.axis < 3; + const int direction = p_axis.axis % 3; - Color axis_color = axis_colors[direction]; - - if (!front) { - axis_color = axis_color.darkened(0.4); - } - Color c = focused ? Color(0.9, 0.9, 0.9) : axis_color; + const Color axis_color = axis_colors[direction]; + const double alpha = focused ? 1.0 : ((p_axis.z_axis + 1.0) / 2.0) * 0.5 + 0.5; + const Color c = focused ? Color(0.9, 0.9, 0.9) : Color(axis_color.r, axis_color.g, axis_color.b, alpha); if (positive) { - Vector2i center = get_size() / 2.0; + // Draw axis lines for the positive axes. + const Vector2i center = get_size() / 2.0; draw_line(center, p_axis.screen_point, c, 1.5 * EDSCALE); - } - if (front) { draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c); - if (positive) { - String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z"); - draw_char(get_theme_font(SNAME("rotation_control"), SNAME("EditorFonts")), p_axis.screen_point + Vector2i(-4, 5) * EDSCALE, axis_name, "", get_theme_font_size(SNAME("rotation_control_size"), SNAME("EditorFonts")), Color(0.0, 0.0, 0.0)); - } + + // Draw the axis letter for the positive axes. + const String axis_name = direction == 0 ? "X" : (direction == 1 ? "Y" : "Z"); + draw_char(get_theme_font(SNAME("rotation_control"), SNAME("EditorFonts")), p_axis.screen_point + Vector2i(-4, 5) * EDSCALE, axis_name, "", get_theme_font_size(SNAME("rotation_control_size"), SNAME("EditorFonts")), Color(0.0, 0.0, 0.0, alpha)); } else { - draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS * (0.55 + (0.2 * (1.0 + p_axis.z_axis))), c); + // Draw an outline around the negative axes. + draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS, c); + draw_circle(p_axis.screen_point, AXIS_CIRCLE_RADIUS * 0.8, c.darkened(0.4)); } } @@ -2738,7 +2735,7 @@ void Node3DEditorViewport::_notification(int p_what) { if (show_fps) { cpu_time_history[cpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_cpu(viewport->get_viewport_rid()); cpu_time_history_index = (cpu_time_history_index + 1) % FRAME_TIME_HISTORY; - float cpu_time = 0.0; + double cpu_time = 0.0; for (int i = 0; i < FRAME_TIME_HISTORY; i++) { cpu_time += cpu_time_history[i]; } @@ -2748,7 +2745,7 @@ void Node3DEditorViewport::_notification(int p_what) { gpu_time_history[gpu_time_history_index] = RS::get_singleton()->viewport_get_measured_render_time_gpu(viewport->get_viewport_rid()); gpu_time_history_index = (gpu_time_history_index + 1) % FRAME_TIME_HISTORY; - float gpu_time = 0.0; + double gpu_time = 0.0; for (int i = 0; i < FRAME_TIME_HISTORY; i++) { gpu_time += gpu_time_history[i]; } @@ -2772,7 +2769,7 @@ void Node3DEditorViewport::_notification(int p_what) { frame_time_gradient->get_color_at_offset( Math::range_lerp(gpu_time, 0, 30, 0, 1))); - const float fps = 1000.0 / gpu_time; + const double fps = 1000.0 / gpu_time; fps_label->set_text(vformat(TTR("FPS: %d"), fps)); // Middle point is at 60 FPS. fps_label->add_theme_color_override( diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index cb2edbcbc1..0c1456aaf8 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -166,9 +166,9 @@ public: }; private: - float cpu_time_history[FRAME_TIME_HISTORY]; + double cpu_time_history[FRAME_TIME_HISTORY]; int cpu_time_history_index; - float gpu_time_history[FRAME_TIME_HISTORY]; + double gpu_time_history[FRAME_TIME_HISTORY]; int gpu_time_history_index; int index; @@ -336,7 +336,7 @@ private: String last_message; String message; - float message_time; + double message_time; void set_message(String p_message, float p_time = 5); diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 63b89aea35..13f7908170 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -88,7 +88,7 @@ Variant Path3DGizmo::get_handle_value(int p_id) const { return ofs; } -void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) { Ref<Curve3D> c = path->get_curve(); if (c.is_null()) { return; @@ -157,7 +157,7 @@ void Path3DGizmo::set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point } } -void Path3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cancel) const { +void Path3DGizmo::commit_handle(int p_id, const Variant &p_restore, bool p_cancel) { Ref<Curve3D> c = path->get_curve(); if (c.is_null()) { return; diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h index 5902500526..b74d7cc59e 100644 --- a/editor/plugins/path_3d_editor_plugin.h +++ b/editor/plugins/path_3d_editor_plugin.h @@ -47,8 +47,8 @@ class Path3DGizmo : public EditorNode3DGizmo { public: virtual String get_handle_name(int p_idx) const override; virtual Variant get_handle_value(int p_id) const override; - virtual void set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - virtual void commit_handle(int p_id, const Variant &p_restore, bool p_cancel = false) const override; + virtual void set_handle(int p_id, Camera3D *p_camera, const Point2 &p_point) override; + virtual void commit_handle(int p_id, const Variant &p_restore, bool p_cancel = false) override; virtual void redraw() override; Path3DGizmo(Path3D *p_path = nullptr); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 4202d8b611..3de2ffc137 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -397,7 +397,7 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi bone_shape->set_transform(capsule_transform); Transform3D body_transform; - body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin); + body_transform.basis = Basis::looking_at(child_rest.origin); body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height)); Transform3D joint_transform; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 452ad126b3..f960da6732 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -408,10 +408,14 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { node->connect("dragged", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_node_dragged), varray(p_id)); Control *custom_editor = nullptr; - int port_offset = 0; + int port_offset = 1; + + Control *content_offset = memnew(Control); + content_offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE)); + node->add_child(content_offset); if (is_group) { - port_offset += 2; + port_offset += 1; } if (is_resizable) { @@ -448,7 +452,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") { //shortcut VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); - node->set_slot(0, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]); + node->set_slot(1, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]); if (!vsnode->is_use_prop_slots()) { return; } @@ -582,7 +586,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (is_curve) { VisualShaderNode::PortType port_left = vsnode->get_input_port_type(0); VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); - node->set_slot(0, true, port_left, type_color[port_left], true, port_right, type_color[port_right]); + node->set_slot(1, true, port_left, type_color[port_left], true, port_right, type_color[port_right]); VisualShaderEditor::get_singleton()->call_deferred(SNAME("_set_node_size"), (int)p_type, p_id, size); } @@ -594,10 +598,6 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { } if (is_group) { - offset = memnew(Control); - offset->set_custom_minimum_size(Size2(0, 6 * EDSCALE)); - node->add_child(offset); - if (group_node->is_editable()) { HBoxContainer *hb2 = memnew(HBoxContainer); @@ -1007,6 +1007,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { const Dictionary vs_version = visual_shader->get_engine_version(); if (!vs_version.has_all(components)) { visual_shader->update_engine_version(engine_version); + print_line(vformat(TTR("The shader (\"%s\") has been updated to correspond Godot %s.%s version."), visual_shader->get_path(), engine_version["major"], engine_version["minor"])); } else { for (int i = 0; i < components.size(); i++) { if (vs_version[components[i]] != engine_version[components[i]]) { diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index a1deae92a4..96fcb4fe29 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -351,51 +351,64 @@ void PropertySelector::_item_selected() { String class_type; if (type != Variant::NIL) { class_type = Variant::get_type_name(type); - - } else { + } else if (base_type != String()) { class_type = base_type; + } else if (instance) { + class_type = instance->get_class(); } DocTools *dd = EditorHelp::get_doc_data(); String text; - if (properties) { - String at_class = class_type; - - while (at_class != String()) { - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class); + while (class_type != String()) { + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(class_type); if (E) { for (int i = 0; i < E->get().properties.size(); i++) { if (E->get().properties[i].name == name) { text = DTR(E->get().properties[i].description); + break; } } } - at_class = ClassDB::get_parent_class(at_class); + if (text != String()) { + break; + } + + // The property may be from a parent class, keep looking. + class_type = ClassDB::get_parent_class(class_type); } } else { - String at_class = class_type; - - while (at_class != String()) { - Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class); + while (class_type != String()) { + Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(class_type); if (E) { for (int i = 0; i < E->get().methods.size(); i++) { if (E->get().methods[i].name == name) { text = DTR(E->get().methods[i].description); + break; } } } - at_class = ClassDB::get_parent_class(at_class); + if (text != String()) { + break; + } + + // The method may be from a parent class, keep looking. + class_type = ClassDB::get_parent_class(class_type); } } - if (text == String()) { - return; + if (text != String()) { + // Display both property name and description, since the help bit may be displayed + // far away from the location (especially if the dialog was resized to be taller). + help_bit->set_text(vformat("[b]%s[/b]: %s", name, text)); + help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 1)); + } else { + // Use nested `vformat()` as translators shouldn't interfere with BBCode tags. + help_bit->set_text(vformat(TTR("No description available for %s."), vformat("[b]%s[/b]", name))); + help_bit->get_rich_text()->set_self_modulate(Color(1, 1, 1, 0.5)); } - - help_bit->set_text(text); } void PropertySelector::_hide_requested() { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index c4d47c7594..8994adf112 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -45,6 +45,7 @@ #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" +#include "editor/shader_create_dialog.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" @@ -1939,12 +1940,31 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) { _update_script_button(); } +void SceneTreeDock::_shader_created(Ref<Shader> p_shader) { + if (selected_shader_material.is_null()) { + return; + } + + Ref<Shader> existing = selected_shader_material->get_shader(); + + editor_data->get_undo_redo().create_action(TTR("Set Shader")); + editor_data->get_undo_redo().add_do_method(selected_shader_material.ptr(), "set_shader", p_shader); + editor_data->get_undo_redo().add_undo_method(selected_shader_material.ptr(), "set_shader", existing); + editor_data->get_undo_redo().commit_action(); +} + void SceneTreeDock::_script_creation_closed() { script_create_dialog->disconnect("script_created", callable_mp(this, &SceneTreeDock::_script_created)); script_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_script_creation_closed)); script_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_script_creation_closed)); } +void SceneTreeDock::_shader_creation_closed() { + shader_create_dialog->disconnect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); + shader_create_dialog->disconnect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->disconnect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); +} + void SceneTreeDock::_toggle_editable_children_from_selection() { List<Node *> selection = editor_selection->get_selected_node_list(); List<Node *>::Element *e = selection.front(); @@ -2896,6 +2916,42 @@ void SceneTreeDock::open_script_dialog(Node *p_for_node, bool p_extend) { } } +void SceneTreeDock::attach_shader_to_selected() { + if (selected_shader_material.is_null()) { + return; + } + + String path = selected_shader_material->get_path(); + if (path == "") { + String root_path; + if (editor_data->get_edited_scene_root()) { + root_path = editor_data->get_edited_scene_root()->get_filename(); + } + String shader_name; + if (selected_shader_material->get_name().is_empty()) { + shader_name = root_path.get_file(); + } else { + shader_name = selected_shader_material->get_name(); + } + if (root_path == "") { + path = String("res://").plus_file(shader_name); + } else { + path = root_path.get_base_dir().plus_file(shader_name); + } + } + + shader_create_dialog->connect("shader_created", callable_mp(this, &SceneTreeDock::_shader_created)); + shader_create_dialog->connect("confirmed", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->connect("cancelled", callable_mp(this, &SceneTreeDock::_shader_creation_closed)); + shader_create_dialog->config(path); + shader_create_dialog->popup_centered(); +} + +void SceneTreeDock::open_shader_dialog(Ref<ShaderMaterial> &p_for_material) { + selected_shader_material = p_for_material; + attach_shader_to_selected(); +} + void SceneTreeDock::open_add_child_dialog() { create_dialog->set_base_type("CanvasItem"); _tool_selected(TOOL_NEW, true); @@ -3267,6 +3323,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel script_create_dialog->set_inheritance_base_type("Node"); add_child(script_create_dialog); + shader_create_dialog = memnew(ShaderCreateDialog); + add_child(shader_create_dialog); + reparent_dialog = memnew(ReparentDialog); add_child(reparent_dialog); reparent_dialog->connect("reparent", callable_mp(this, &SceneTreeDock::_node_reparent)); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 4952122cb7..ccdc0a3786 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -49,6 +49,7 @@ #include "scene_tree_editor.h" class EditorNode; +class ShaderCreateDialog; class SceneTreeDock : public VBoxContainer { GDCLASS(SceneTreeDock, VBoxContainer); @@ -138,6 +139,7 @@ class SceneTreeDock : public VBoxContainer { HashMap<String, Map<RES, RES>> clipboard_resource_remap; ScriptCreateDialog *script_create_dialog; + ShaderCreateDialog *shader_create_dialog; AcceptDialog *accept; ConfirmationDialog *delete_dialog; ConfirmationDialog *editable_instance_remove_dialog; @@ -166,6 +168,8 @@ class SceneTreeDock : public VBoxContainer { VBoxContainer *create_root_dialog; String selected_favorite_root; + Ref<ShaderMaterial> selected_shader_material; + void _add_children_to_popup(Object *p_obj, int p_depth); void _node_reparent(NodePath p_path, bool p_keep_global_xform); @@ -192,7 +196,9 @@ class SceneTreeDock : public VBoxContainer { void _node_selected(); void _node_renamed(); void _script_created(Ref<Script> p_script); + void _shader_created(Ref<Shader> p_shader); void _script_creation_closed(); + void _shader_creation_closed(); void _delete_confirm(bool p_cut = false); @@ -288,6 +294,9 @@ public: void attach_script_to_selected(bool p_extend); void open_script_dialog(Node *p_for_node, bool p_extend); + void attach_shader_to_selected(); + void open_shader_dialog(Ref<ShaderMaterial> &p_for_material); + void open_add_child_dialog(); void open_instance_child_dialog(); diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp new file mode 100644 index 0000000000..7e6f154fab --- /dev/null +++ b/editor/shader_create_dialog.cpp @@ -0,0 +1,627 @@ +/*************************************************************************/ +/* shader_create_dialog.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "shader_create_dialog.h" +#include "editor/editor_scale.h" +#include "scene/resources/visual_shader.h" +#include "servers/rendering/shader_types.h" + +void ShaderCreateDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + _update_theme(); + + String last_lang = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_language", ""); + if (!last_lang.is_empty()) { + for (int i = 0; i < language_menu->get_item_count(); i++) { + if (language_menu->get_item_text(i) == last_lang) { + language_menu->select(i); + current_language = i; + break; + } + } + } else { + language_menu->select(default_language); + } + + current_mode = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_mode", 0); + mode_menu->select(current_mode); + } break; + case NOTIFICATION_THEME_CHANGED: { + _update_theme(); + } break; + } +} + +void ShaderCreateDialog::_update_theme() { + Ref<Texture2D> shader_icon = gc->get_theme_icon(SNAME("Shader"), SNAME("EditorIcons")); + if (shader_icon.is_valid()) { + language_menu->set_item_icon(0, shader_icon); + } + + Ref<Texture2D> visual_shader_icon = gc->get_theme_icon(SNAME("VisualShader"), SNAME("EditorIcons")); + if (visual_shader_icon.is_valid()) { + language_menu->set_item_icon(1, visual_shader_icon); + } + + path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"))); + status_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree"))); +} + +void ShaderCreateDialog::_update_language_info() { + language_data.clear(); + + for (int i = 0; i < SHADER_TYPE_MAX; i++) { + ShaderTypeData data; + if (i == int(SHADER_TYPE_TEXT)) { + data.use_templates = true; + data.extensions.push_back("gdshader"); + data.default_extension = "gdshader"; + } else { + data.default_extension = "tres"; + } + data.extensions.push_back("res"); + data.extensions.push_back("tres"); + language_data.push_back(data); + } +} + +void ShaderCreateDialog::_path_hbox_sorted() { + if (is_visible()) { + int filename_start_pos = initial_base_path.rfind("/") + 1; + int filename_end_pos = initial_base_path.length(); + + if (!is_built_in) { + file_path->select(filename_start_pos, filename_end_pos); + } + + file_path->set_caret_column(file_path->get_text().length()); + file_path->set_caret_column(filename_start_pos); + + file_path->grab_focus(); + } +} + +void ShaderCreateDialog::_mode_changed(int p_mode) { + current_mode = p_mode; + EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_mode", p_mode); +} + +void ShaderCreateDialog::_template_changed(int p_template) { + current_template = p_template; + EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_template", p_template); +} + +void ShaderCreateDialog::ok_pressed() { + if (is_new_shader_created) { + _create_new(); + } else { + _load_exist(); + } + + is_new_shader_created = true; + _update_dialog(); +} + +void ShaderCreateDialog::_create_new() { + RES shader; + + if (language_menu->get_selected() == int(SHADER_TYPE_TEXT)) { + Ref<Shader> text_shader; + text_shader.instantiate(); + shader = text_shader; + + StringBuilder code; + code += vformat("shader_type %s;\n", mode_menu->get_text().replace(" ", "").camelcase_to_underscore()); + + if (current_template == 0) { // Default template. + code += "\n"; + switch (current_mode) { + case Shader::MODE_SPATIAL: + code += "void fragment() {\n"; + code += "\t// Place fragment code here.\n"; + code += "}\n"; + break; + case Shader::MODE_CANVAS_ITEM: + code += "void fragment() {\n"; + code += "\t// Place fragment code here.\n"; + code += "}\n"; + break; + case Shader::MODE_PARTICLES: + code += "void start() {\n"; + code += "\t// Place start code here.\n"; + code += "}\n"; + code += "\n"; + code += "void process() {\n"; + code += "\t// Place process code here.\n"; + code += "}\n"; + break; + case Shader::MODE_SKY: + code += "void sky() {\n"; + code += "\t// Place sky code here.\n"; + code += "}\n"; + break; + } + } + text_shader->set_code(code.as_string()); + } else { + Ref<VisualShader> visual_shader; + visual_shader.instantiate(); + shader = visual_shader; + visual_shader->set_engine_version(Engine::get_singleton()->get_version_info()); + visual_shader->set_mode(Shader::Mode(current_mode)); + } + + if (!is_built_in) { + String lpath = ProjectSettings::get_singleton()->localize_path(file_path->get_text()); + shader->set_path(lpath); + Error err = ResourceSaver::save(lpath, shader, ResourceSaver::FLAG_CHANGE_PATH); + if (err != OK) { + alert->set_text(TTR("Error - Could not create shader in filesystem.")); + alert->popup_centered(); + return; + } + } + + emit_signal("shader_created", shader); + hide(); +} + +void ShaderCreateDialog::_load_exist() { + String path = file_path->get_text(); + RES p_shader = ResourceLoader::load(path, "Shader"); + if (p_shader.is_null()) { + alert->set_text(vformat(TTR("Error loading shader from %s"), path)); + alert->popup_centered(); + return; + } + + emit_signal("shader_created", p_shader); + hide(); +} + +void ShaderCreateDialog::_language_changed(int p_language) { + current_language = p_language; + ShaderTypeData data = language_data[p_language]; + + String selected_ext = "." + data.default_extension; + String path = file_path->get_text(); + String extension = ""; + + if (path != "") { + if (path.find(".") != -1) { + extension = path.get_extension(); + } + if (extension.length() == 0) { + path += selected_ext; + } else { + path = path.get_basename() + selected_ext; + } + } else { + path = "shader" + selected_ext; + } + _path_changed(path); + file_path->set_text(path); + + template_menu->set_disabled(!data.use_templates); + template_menu->clear(); + + if (data.use_templates) { + int last_template = EditorSettings::get_singleton()->get_project_metadata("shader_setup", "last_selected_template", 0); + + template_menu->add_item(TTR("Default")); + template_menu->add_item(TTR("Empty")); + + template_menu->select(last_template); + current_template = last_template; + } else { + template_menu->add_item(TTR("N/A")); + } + + EditorSettings::get_singleton()->set_project_metadata("shader_setup", "last_selected_language", language_menu->get_item_text(language_menu->get_selected())); + _update_dialog(); +} + +void ShaderCreateDialog::_built_in_toggled(bool p_enabled) { + is_built_in = p_enabled; + if (p_enabled) { + is_new_shader_created = true; + } else { + _path_changed(file_path->get_text()); + } + _update_dialog(); +} + +void ShaderCreateDialog::_browse_path() { + file_browse->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); + file_browse->set_title(TTR("Open Shader / Choose Location")); + file_browse->get_ok_button()->set_text(TTR("Open")); + + file_browse->set_disable_overwrite_warning(true); + file_browse->clear_filters(); + + List<String> extensions = language_data[language_menu->get_selected()].extensions; + + for (const String &E : extensions) { + file_browse->add_filter("*." + E); + } + + file_browse->set_current_path(file_path->get_text()); + file_browse->popup_file_dialog(); +} + +void ShaderCreateDialog::_file_selected(const String &p_file) { + String p = ProjectSettings::get_singleton()->localize_path(p_file); + file_path->set_text(p); + _path_changed(p); + + String filename = p.get_file().get_basename(); + int select_start = p.rfind(filename); + file_path->select(select_start, select_start + filename.length()); + file_path->set_caret_column(select_start + filename.length()); + file_path->grab_focus(); +} + +void ShaderCreateDialog::_path_changed(const String &p_path) { + if (is_built_in) { + return; + } + + is_path_valid = false; + is_new_shader_created = true; + + String path_error = _validate_path(p_path); + if (path_error != "") { + _msg_path_valid(false, path_error); + _update_dialog(); + return; + } + + DirAccessRef f = DirAccess::create(DirAccess::ACCESS_RESOURCES); + String p = ProjectSettings::get_singleton()->localize_path(p_path.strip_edges()); + if (f->file_exists(p)) { + is_new_shader_created = false; + _msg_path_valid(true, TTR("File exists, it will be reused.")); + } + + is_path_valid = true; + _update_dialog(); +} + +void ShaderCreateDialog::_path_submitted(const String &p_path) { + ok_pressed(); +} + +void ShaderCreateDialog::config(const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled) { + if (p_base_path != "") { + initial_base_path = p_base_path.get_basename(); + file_path->set_text(initial_base_path + "." + language_data[language_menu->get_selected()].default_extension); + current_language = language_menu->get_selected(); + } else { + initial_base_path = ""; + file_path->set_text(""); + } + file_path->deselect(); + + built_in_enabled = p_built_in_enabled; + load_enabled = p_load_enabled; + + _language_changed(current_language); + _path_changed(file_path->get_text()); +} + +String ShaderCreateDialog::_validate_path(const String &p_path) { + String p = p_path.strip_edges(); + + if (p == "") { + return TTR("Path is empty."); + } + if (p.get_file().get_basename() == "") { + return TTR("Filename is empty."); + } + + p = ProjectSettings::get_singleton()->localize_path(p); + if (!p.begins_with("res://")) { + return TTR("Path is not local."); + } + + DirAccessRef d = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (d->change_dir(p.get_base_dir()) != OK) { + return TTR("Invalid base path."); + } + + DirAccessRef f = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (f->dir_exists(p)) { + return TTR("A directory with the same name exists."); + } + + String extension = p.get_extension(); + Set<String> extensions; + + for (int i = 0; i < SHADER_TYPE_MAX; i++) { + for (const String &ext : language_data[i].extensions) { + if (!extensions.has(ext)) { + extensions.insert(ext); + } + } + } + + ShaderTypeData data = language_data[language_menu->get_selected()]; + + bool found = false; + bool match = false; + + for (const String &ext : extensions) { + if (ext.nocasecmp_to(extension) == 0) { + found = true; + for (const String &lang_ext : language_data[current_language].extensions) { + if (lang_ext.nocasecmp_to(extension) == 0) { + match = true; + break; + } + } + break; + } + } + + if (!found) { + return TTR("Invalid extension."); + } + if (!match) { + return TTR("Wrong extension chosen."); + } + + return ""; +} + +void ShaderCreateDialog::_msg_script_valid(bool valid, const String &p_msg) { + error_label->set_text("- " + p_msg); + if (valid) { + error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); + } else { + error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor")); + } +} + +void ShaderCreateDialog::_msg_path_valid(bool valid, const String &p_msg) { + path_error_label->set_text("- " + p_msg); + if (valid) { + path_error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); + } else { + path_error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor")); + } +} + +void ShaderCreateDialog::_update_dialog() { + bool shader_ok = true; + + if (!is_built_in && !is_path_valid) { + _msg_script_valid(false, TTR("Invalid path.")); + shader_ok = false; + } + if (shader_ok) { + _msg_script_valid(true, TTR("Shader path/name is valid.")); + } + if (!built_in_enabled) { + internal->set_pressed(false); + } + + if (is_built_in) { + file_path->set_editable(false); + path_button->set_disabled(true); + re_check_path = true; + } else { + file_path->set_editable(true); + path_button->set_disabled(false); + if (re_check_path) { + re_check_path = false; + _path_changed(file_path->get_text()); + } + } + + internal->set_disabled(!built_in_enabled); + + builtin_warning_label->set_visible(is_built_in); + + if (is_built_in) { + get_ok_button()->set_text(TTR("Create")); + _msg_path_valid(true, TTR("Built-in shader (into scene file).")); + } else if (is_new_shader_created) { + get_ok_button()->set_text(TTR("Create")); + if (is_path_valid) { + _msg_path_valid(true, TTR("Will create a new shader file.")); + } + } else if (load_enabled) { + get_ok_button()->set_text(TTR("Load")); + if (is_path_valid) { + _msg_path_valid(true, TTR("Will load an existing shader file.")); + } + } else { + get_ok_button()->set_text(TTR("Create")); + _msg_path_valid(false, TTR("Shader file already exists.")); + + shader_ok = false; + } + + get_ok_button()->set_disabled(!shader_ok); + + Callable entered_call = callable_mp(this, &ShaderCreateDialog::_path_submitted); + if (shader_ok) { + if (!file_path->is_connected("text_submitted", entered_call)) { + file_path->connect("text_submitted", entered_call); + } + } else if (file_path->is_connected("text_submitted", entered_call)) { + file_path->disconnect("text_submitted", entered_call); + } +} + +void ShaderCreateDialog::_bind_methods() { + ClassDB::bind_method(D_METHOD("config", "path", "built_in_enabled", "load_enabled"), &ShaderCreateDialog::config, DEFVAL(true), DEFVAL(true)); + + ADD_SIGNAL(MethodInfo("shader_created", PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"))); +} + +ShaderCreateDialog::ShaderCreateDialog() { + _update_language_info(); + + // Main Controls. + + gc = memnew(GridContainer); + gc->set_columns(2); + + // Error Fields. + + VBoxContainer *vb = memnew(VBoxContainer); + + error_label = memnew(Label); + vb->add_child(error_label); + + path_error_label = memnew(Label); + vb->add_child(path_error_label); + + builtin_warning_label = memnew(Label); + builtin_warning_label->set_text( + TTR("Note: Built-in shaders can't be edited using an external editor.")); + vb->add_child(builtin_warning_label); + builtin_warning_label->set_autowrap_mode(Label::AUTOWRAP_WORD_SMART); + builtin_warning_label->hide(); + + status_panel = memnew(PanelContainer); + status_panel->set_h_size_flags(Control::SIZE_FILL); + status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL); + status_panel->add_child(vb); + + // Spacing. + + Control *spacing = memnew(Control); + spacing->set_custom_minimum_size(Size2(0, 10 * EDSCALE)); + + vb = memnew(VBoxContainer); + vb->add_child(gc); + vb->add_child(spacing); + vb->add_child(status_panel); + add_child(vb); + + // Language. + + language_menu = memnew(OptionButton); + language_menu->set_custom_minimum_size(Size2(250, 0) * EDSCALE); + language_menu->set_h_size_flags(Control::SIZE_EXPAND_FILL); + gc->add_child(memnew(Label(TTR("Language:")))); + gc->add_child(language_menu); + + for (int i = 0; i < SHADER_TYPE_MAX; i++) { + String language; + bool invalid = false; + switch (i) { + case SHADER_TYPE_TEXT: + language = "Shader"; + default_language = i; + break; + case SHADER_TYPE_VISUAL: + language = "VisualShader"; + break; + case SHADER_TYPE_MAX: + invalid = true; + break; + default: + invalid = true; + break; + } + if (invalid) { + continue; + } + language_menu->add_item(language); + } + if (default_language >= 0) { + language_menu->select(default_language); + } + current_language = default_language; + language_menu->connect("item_selected", callable_mp(this, &ShaderCreateDialog::_language_changed)); + + // Modes. + + mode_menu = memnew(OptionButton); + for (const String &type_name : ShaderTypes::get_singleton()->get_types_list()) { + mode_menu->add_item(type_name.capitalize()); + } + gc->add_child(memnew(Label(TTR("Mode:")))); + gc->add_child(mode_menu); + mode_menu->connect("item_selected", callable_mp(this, &ShaderCreateDialog::_mode_changed)); + + // Templates. + + template_menu = memnew(OptionButton); + gc->add_child(memnew(Label(TTR("Template:")))); + gc->add_child(template_menu); + template_menu->connect("item_selected", callable_mp(this, &ShaderCreateDialog::_template_changed)); + + // Built-in Shader. + + internal = memnew(CheckBox); + internal->set_text(TTR("On")); + internal->connect("toggled", callable_mp(this, &ShaderCreateDialog::_built_in_toggled)); + gc->add_child(memnew(Label(TTR("Built-in Shader:")))); + gc->add_child(internal); + + // Path. + + HBoxContainer *hb = memnew(HBoxContainer); + hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->connect("sort_children", callable_mp(this, &ShaderCreateDialog::_path_hbox_sorted)); + file_path = memnew(LineEdit); + file_path->connect("text_changed", callable_mp(this, &ShaderCreateDialog::_path_changed)); + file_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hb->add_child(file_path); + path_button = memnew(Button); + path_button->connect("pressed", callable_mp(this, &ShaderCreateDialog::_browse_path)); + hb->add_child(path_button); + gc->add_child(memnew(Label(TTR("Path:")))); + gc->add_child(hb); + + // Dialog Setup. + + file_browse = memnew(EditorFileDialog); + file_browse->connect("file_selected", callable_mp(this, &ShaderCreateDialog::_file_selected)); + file_browse->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + add_child(file_browse); + + alert = memnew(AcceptDialog); + alert->get_label()->set_autowrap_mode(Label::AUTOWRAP_WORD_SMART); + alert->get_label()->set_align(Label::ALIGN_CENTER); + alert->get_label()->set_valign(Label::VALIGN_CENTER); + alert->get_label()->set_custom_minimum_size(Size2(325, 60) * EDSCALE); + add_child(alert); + + get_ok_button()->set_text(TTR("Create")); + set_hide_on_ok(false); + + set_title(TTR("Create Shader")); +} diff --git a/editor/shader_create_dialog.h b/editor/shader_create_dialog.h new file mode 100644 index 0000000000..6962fa3d8d --- /dev/null +++ b/editor/shader_create_dialog.h @@ -0,0 +1,115 @@ +/*************************************************************************/ +/* shader_create_dialog.h */ +/*************************************************************************/ +/* 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 SHADER_CREATE_DIALOG_H +#define SHADER_CREATE_DIALOG_H + +#include "editor/editor_file_dialog.h" +#include "editor/editor_settings.h" +#include "scene/gui/check_box.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/grid_container.h" +#include "scene/gui/line_edit.h" +#include "scene/gui/option_button.h" +#include "scene/gui/panel_container.h" + +class ShaderCreateDialog : public ConfirmationDialog { + GDCLASS(ShaderCreateDialog, ConfirmationDialog); + + enum ShaderType { + SHADER_TYPE_TEXT, + SHADER_TYPE_VISUAL, + SHADER_TYPE_MAX, + }; + + struct ShaderTypeData { + List<String> extensions; + String default_extension; + bool use_templates = false; + }; + + List<ShaderTypeData> language_data; + + GridContainer *gc = nullptr; + Label *error_label = nullptr; + Label *path_error_label = nullptr; + Label *builtin_warning_label = nullptr; + PanelContainer *status_panel = nullptr; + OptionButton *language_menu = nullptr; + OptionButton *mode_menu = nullptr; + OptionButton *template_menu = nullptr; + CheckBox *internal = nullptr; + LineEdit *file_path = nullptr; + Button *path_button = nullptr; + EditorFileDialog *file_browse = nullptr; + AcceptDialog *alert = nullptr; + + String initial_base_path; + bool is_new_shader_created = true; + bool is_path_valid = false; + bool is_built_in = false; + bool built_in_enabled = true; + bool load_enabled = false; + bool re_check_path = false; + int current_language = -1; + int default_language = -1; + int current_mode = 0; + int current_template = 0; + + virtual void _update_language_info(); + + void _path_hbox_sorted(); + void _path_changed(const String &p_path = String()); + void _path_submitted(const String &p_path = String()); + void _language_changed(int p_language = 0); + void _built_in_toggled(bool p_enabled); + void _template_changed(int p_template = 0); + void _mode_changed(int p_mode = 0); + void _browse_path(); + void _file_selected(const String &p_file); + String _validate_path(const String &p_path); + virtual void ok_pressed() override; + void _create_new(); + void _load_exist(); + void _msg_script_valid(bool valid, const String &p_msg = String()); + void _msg_path_valid(bool valid, const String &p_msg = String()); + void _update_dialog(); + +protected: + void _update_theme(); + void _notification(int p_what); + static void _bind_methods(); + +public: + void config(const String &p_base_path, bool p_built_in_enabled = true, bool p_load_enabled = true); + ShaderCreateDialog(); +}; + +#endif diff --git a/methods.py b/methods.py index 13851d8315..970bd10aa3 100644 --- a/methods.py +++ b/methods.py @@ -828,6 +828,10 @@ def using_clang(env): return "clang" in os.path.basename(env["CC"]) +def using_emcc(env): + return "emcc" in os.path.basename(env["CC"]) + + def show_progress(env): import sys from SCons.Script import Progress, Command, AlwaysBuild diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub index bfac0df5b0..ba57de303e 100644 --- a/modules/bullet/SCsub +++ b/modules/bullet/SCsub @@ -12,6 +12,8 @@ thirdparty_obj = [] if env["builtin_bullet"]: # Build only version 2 for now (as of 2.89) # Sync file list with relevant upstream CMakeLists.txt for each folder. + if env["float"] == "64": + env.Append(CPPDEFINES=["BT_USE_DOUBLE_PRECISION=1"]) thirdparty_dir = "#thirdparty/bullet/" bullet2_src = [ diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index e07be14c5b..fc876a81cf 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -842,12 +842,12 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod return BulletPhysicsDirectBodyState3D::get_singleton(body); } -bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); - return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes, p_exclude); } int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index d34d619ba2..7f0934e679 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -253,7 +253,7 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; - virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override; virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; /* SOFT BODY API */ diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp index 399b102284..1f962772e7 100644 --- a/modules/bullet/godot_result_callbacks.cpp +++ b/modules/bullet/godot_result_callbacks.cpp @@ -135,6 +135,10 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) { return false; } + + if (m_exclude->has(gObj->get_self())) { + return false; + } } return true; } else { diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h index 9216322108..96a649d77a 100644 --- a/modules/bullet/godot_result_callbacks.h +++ b/modules/bullet/godot_result_callbacks.h @@ -100,11 +100,13 @@ public: struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: const RigidBodyBullet *m_self_object; + const Set<RID> *m_exclude; const bool m_infinite_inertia; - GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) : + GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia, const Set<RID> *p_exclude) : btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld), m_self_object(p_self_object), + m_exclude(p_exclude), m_infinite_inertia(p_infinite_inertia) {} virtual bool needsCollision(btBroadphaseProxy *proxy0) const; diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index ce39d4f0df..0d2cd1f5a0 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -114,6 +114,16 @@ Transform3D BulletPhysicsDirectBodyState3D::get_transform() const { return body->get_transform(); } +Vector3 BulletPhysicsDirectBodyState3D::get_velocity_at_local_position(const Vector3 &p_position) const { + btVector3 local_position; + G_TO_B(p_position, local_position); + + Vector3 velocity; + B_TO_G(body->btBody->getVelocityInLocalPoint(local_position), velocity); + + return velocity; +} + void BulletPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) { body->apply_central_force(p_force); } diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index 606df7134b..5e102d8b05 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -110,6 +110,8 @@ public: virtual void set_transform(const Transform3D &p_transform) override; virtual Transform3D get_transform() const override; + virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override; + virtual void add_central_force(const Vector3 &p_force) override; virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override; virtual void add_torque(const Vector3 &p_torque) override; diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 583900e6bc..c6d835742d 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat; static Ref<StandardMaterial3D> blue_mat; #endif -bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) { #if debug_test_motion /// Yes I know this is not good, but I've used it as fast debugging hack. /// I'm leaving it here just for speedup the other eventual debugs @@ -948,7 +948,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p btVector3 initial_recover_motion(0, 0, 0); { /// Phase one - multi shapes depenetration using margin for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) { - if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion)) { + if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion, nullptr, p_exclude)) { break; } } @@ -1000,7 +1000,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p break; } - GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia); + GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia, &p_exclude); btResult.m_collisionFilterGroup = p_body->get_collision_layer(); btResult.m_collisionFilterMask = p_body->get_collision_mask(); @@ -1023,7 +1023,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p btVector3 __rec(0, 0, 0); RecoverResult r_recover_result; - has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result); + has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result, p_exclude); // Parse results if (r_result) { @@ -1173,7 +1173,7 @@ public: } }; -bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) { +bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result, const Set<RID> &p_exclude) { // Calculate the cumulative AABB of all shapes of the kinematic body btVector3 aabb_min, aabb_max; bool shapes_found = false; @@ -1242,6 +1242,12 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) { btCollisionObject *otherObject = recover_broad_result.results[i].collision_object; + + CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer()); + if (p_exclude.has(gObj->get_self())) { + continue; + } + if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) { otherObject->activate(); // Force activation of hitten rigid, soft body continue; diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 36d0538e6b..2070e0e633 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -188,7 +188,7 @@ public: real_t get_linear_damp() const { return linear_damp; } real_t get_angular_damp() const { return angular_damp; } - bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); + bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>()); int test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); private: @@ -209,7 +209,7 @@ private: RecoverResult() {} }; - bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr); + bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr, const Set<RID> &p_exclude = Set<RID>()); /// This is an API that recover a kinematic object from penetration /// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr); diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 42f8b9f163..2f8b354bb7 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -98,7 +98,7 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo return Variant(); } -void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const { +void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); Transform3D gt = cs->get_global_transform(); @@ -201,7 +201,7 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i } } -void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const { +void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere3D>(cs)) { diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 847313c0b4..2a6ab91102 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -47,8 +47,8 @@ public: virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id) const override; virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id) const override; - virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) const override; - virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) const override; + virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, Camera3D *p_camera, const Point2 &p_point) override; + virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, const Variant &p_restore, bool p_cancel) override; CSGShape3DGizmoPlugin(); }; diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index de7de09f00..0106f230eb 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -83,14 +83,14 @@ private: Vector<Vector3> vertices; Vector<Vector3> normals; Vector<Vector2> uvs; - Vector<float> tans; + Vector<real_t> tans; Ref<Material> material; int last_added = 0; Vector3 *verticesw = nullptr; Vector3 *normalsw = nullptr; Vector2 *uvsw = nullptr; - float *tansw = nullptr; + real_t *tansw = nullptr; }; //mikktspace callbacks diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp index aa0e09bcde..38ca38385c 100644 --- a/modules/enet/enet_multiplayer_peer.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -242,8 +242,8 @@ bool ENetMultiplayerPeer::_poll_client() { } switch (ret) { case ENetConnection::EVENT_CONNECT: { - emit_signal(SNAME("peer_connected"), 1); connection_status = CONNECTION_CONNECTED; + emit_signal(SNAME("peer_connected"), 1); emit_signal(SNAME("connection_succeeded")); return false; } diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index 8b4b1e08b3..dcea476275 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -433,7 +433,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) { { // Sort - real_t *weights_ptr = vm->weights.ptrw(); + float *weights_ptr = vm->weights.ptrw(); int *bones_ptr = vm->bones.ptrw(); for (int i = 0; i < vm->weights.size(); i += 1) { for (int x = i + 1; x < vm->weights.size(); x += 1) { @@ -449,7 +449,7 @@ void FBXMeshData::sanitize_vertex_weights(const ImportState &state) { // Resize vm->weights.resize(max_vertex_influence_count); vm->bones.resize(max_vertex_influence_count); - real_t *weights_ptr = vm->weights.ptrw(); + float *weights_ptr = vm->weights.ptrw(); int *bones_ptr = vm->bones.ptrw(); for (int i = initial_size; i < max_vertex_influence_count; i += 1) { weights_ptr[i] = 0.0; diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h index 7486c5c59c..24db4a5469 100644 --- a/modules/fbx/data/fbx_mesh_data.h +++ b/modules/fbx/data/fbx_mesh_data.h @@ -64,7 +64,7 @@ struct SurfaceData { }; struct VertexWeightMapping { - Vector<real_t> weights; + Vector<float> weights; Vector<int> bones; // This extra vector is used because the bone id is computed in a second step. // TODO Get rid of this extra step is a good idea. diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub index fc2535a6ca..476cb9cf2a 100644 --- a/modules/freetype/SCsub +++ b/modules/freetype/SCsub @@ -80,6 +80,7 @@ if env["builtin_freetype"]: # Forcibly undefine this macro so SIMD is not used in this file, # since currently unsupported in WASM tmp_env = env_freetype.Clone() + tmp_env.disable_warnings() tmp_env.Append(CPPFLAGS=["-U__OPTIMIZE__"]) sfnt = tmp_env.Object(sfnt) thirdparty_sources += [sfnt] diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index f3a0e9603f..26d3aed702 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -114,9 +114,25 @@ void NativeScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) #endif bool NativeScript::inherits_script(const Ref<Script> &p_script) const { -#ifndef _MSC_VER -#warning inheritance needs to be implemented in NativeScript -#endif + Ref<NativeScript> ns = p_script; + if (ns.is_null()) { + return false; + } + + const NativeScriptDesc *other_s = ns->get_script_desc(); + if (!other_s) { + return false; + } + + const NativeScriptDesc *s = get_script_desc(); + + while (s) { + if (s == other_s) { + return true; + } + s = s->base_data; + } + return false; } diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index 7fc8178e34..5380858582 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -139,9 +139,20 @@ bool PluginScript::can_instantiate() const { } bool PluginScript::inherits_script(const Ref<Script> &p_script) const { -#ifndef _MSC_VER -#warning inheritance needs to be implemented in PluginScript -#endif + Ref<PluginScript> ps = p_script; + if (ps.is_null()) { + return false; + } + + const PluginScript *s = this; + + while (s) { + if (s == p_script.ptr()) { + return true; + } + s = Object::cast_to<PluginScript>(s->_ref_base_parent.ptr()); + } + return false; } diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp index 81dd570bcb..d54b1a47df 100644 --- a/modules/gdnative/text/text_server_gdnative.cpp +++ b/modules/gdnative/text/text_server_gdnative.cpp @@ -449,12 +449,12 @@ bool TextServerGDNative::shaped_text_add_string(RID p_shaped, const String &p_te return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language); } -bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { +bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { ERR_FAIL_COND_V(interface == nullptr, false); return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length); } -bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) { +bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { ERR_FAIL_COND_V(interface == nullptr, false); return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align); } diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h index 7a0725f3d9..a2eb944499 100644 --- a/modules/gdnative/text/text_server_gdnative.h +++ b/modules/gdnative/text/text_server_gdnative.h @@ -154,8 +154,8 @@ public: virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override; virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; virtual RID shaped_text_get_parent(RID p_shaped) const override; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 7c9d08b782..fe827a5b72 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -107,7 +107,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D // Locate class by constructing the path to it and following that path GDScriptParser::ClassNode *class_type = p_datatype.class_type; if (class_type) { - if (class_type->fqcn.begins_with(main_script->path) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) { + if ((!main_script->path.is_empty() && class_type->fqcn.begins_with(main_script->path)) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) { // Local class. List<StringName> names; while (class_type->outer) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 466ddb4b10..a500dfd51a 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -168,7 +168,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); // Networking. - register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_MASTER>, 4, true); + register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<MultiplayerAPI::RPC_MODE_PUPPET>, 4, true); // TODO: Warning annotations. } diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index c0013ac23a..9574c765bc 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -431,9 +431,13 @@ void GDScriptTextDocument::sync_script_content(const String &p_path, const Strin GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content); EditorFileSystem::get_singleton()->update_file(path); - Ref<GDScript> script = ResourceLoader::load(path); - script->load_source_code(path); - script->reload(true); + Error error; + Ref<GDScript> script = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &error); + if (error == OK) { + if (script->load_source_code(path) == OK) { + script->reload(true); + } + } } void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) { diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 148aeec47a..1512b4bb89 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -520,8 +520,31 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S if (const ExtendGDScriptParser *parser = get_parse_result(path)) { Node *owner_scene_node = _get_owner_scene_node(path); + + Array stack; + Node *current = nullptr; + if (owner_scene_node != nullptr) { + stack.push_back(owner_scene_node); + + while (!stack.is_empty()) { + current = stack.pop_back(); + Ref<GDScript> script = current->get_script(); + if (script.is_valid() && script->get_path() == path) { + break; + } + for (int i = 0; i < current->get_child_count(); ++i) { + stack.push_back(current->get_child(i)); + } + } + + Ref<GDScript> script = current->get_script(); + if (!script.is_valid() || script->get_path() != path) { + current = owner_scene_node; + } + } + String code = parser->get_text_for_completion(p_params.position); - GDScriptLanguage::get_singleton()->complete_code(code, path, owner_scene_node, r_options, forced, call_hint); + GDScriptLanguage::get_singleton()->complete_code(code, path, current, r_options, forced, call_hint); if (owner_scene_node) { memdelete(owner_scene_node); } diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index be44f66423..ff0579a11c 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -43,6 +43,7 @@ #include "gltf_texture.h" #include "core/crypto/crypto_core.h" +#include "core/error/error_macros.h" #include "core/io/dir_access.h" #include "core/io/file_access.h" #include "core/io/json.h" @@ -4469,9 +4470,9 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { const Dictionary &spot = d["spot"]; light->inner_cone_angle = spot["innerConeAngle"]; light->outer_cone_angle = spot["outerConeAngle"]; - ERR_FAIL_COND_V_MSG(light->inner_cone_angle >= light->outer_cone_angle, ERR_PARSE_ERROR, "The inner angle must be smaller than the outer angle."); + ERR_CONTINUE_MSG(light->inner_cone_angle >= light->outer_cone_angle, "The inner angle must be smaller than the outer angle."); } else if (type != "point" && type != "directional") { - ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Light type is unknown."); + ERR_CONTINUE_MSG(ERR_PARSE_ERROR, "Light type is unknown."); } state->lights.push_back(light); @@ -5380,15 +5381,16 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent // and attach it to the bone_attachment scene_parent = bone_attachment; } - - // We still have not managed to make a node if (gltf_node->mesh >= 0) { current_node = _generate_mesh_instance(state, scene_parent, node_index); } else if (gltf_node->camera >= 0) { current_node = _generate_camera(state, scene_parent, node_index); } else if (gltf_node->light >= 0) { current_node = _generate_light(state, scene_parent, node_index); - } else { + } + + // We still have not managed to make a node. + if (!current_node) { current_node = _generate_spatial(state, scene_parent, node_index); } diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs index 897f1b2822..5f35d506de 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs @@ -73,7 +73,7 @@ namespace GodotTools.Build GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message); } - if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Rebuild"})) + if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] { "Rebuild" })) return; // Build failed // Notify running game for hot-reload @@ -92,7 +92,7 @@ namespace GodotTools.Build if (!File.Exists(GodotSharpDirs.ProjectSlnPath)) return; // No solution to build - BuildManager.BuildProjectBlocking("Debug", targets: new[] {"Clean"}); + BuildManager.BuildProjectBlocking("Debug", targets: new[] { "Clean" }); } private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed; @@ -129,10 +129,10 @@ namespace GodotTools.Build RectMinSize = new Vector2(0, 228) * EditorScale; SizeFlagsVertical = (int)SizeFlags.ExpandFill; - var toolBarHBox = new HBoxContainer {SizeFlagsHorizontal = (int)SizeFlags.ExpandFill}; + var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill }; AddChild(toolBarHBox); - buildMenuBtn = new MenuButton {Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons")}; + buildMenuBtn = new MenuButton { Text = "Build", Icon = GetThemeIcon("Play", "EditorIcons") }; toolBarHBox.AddChild(buildMenuBtn); var buildMenu = buildMenuBtn.GetPopup(); @@ -183,10 +183,14 @@ namespace GodotTools.Build { base._Notification(what); - if (what == NotificationThemeChanged) { - buildMenuBtn.Icon = GetThemeIcon("Play", "EditorIcons"); - errorsBtn.Icon = GetThemeIcon("StatusError", "EditorIcons"); - warningsBtn.Icon = GetThemeIcon("NodeWarning", "EditorIcons"); + if (what == NotificationThemeChanged) + { + if (buildMenuBtn != null) + buildMenuBtn.Icon = GetThemeIcon("Play", "EditorIcons"); + if (errorsBtn != null) + errorsBtn.Icon = GetThemeIcon("StatusError", "EditorIcons"); + if (warningsBtn != null) + warningsBtn.Icon = GetThemeIcon("NodeWarning", "EditorIcons"); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 8271b43b48..968f853c2d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -207,7 +207,7 @@ namespace Godot } } - public Quaternion RotationQuaternion() + public Quaternion GetRotationQuaternion() { Basis orthonormalizedBasis = Orthonormalized(); real_t det = orthonormalizedBasis.Determinant(); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs index 213fc181c1..61a34bfc87 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; namespace Godot.Collections { @@ -25,6 +26,11 @@ namespace Godot.Collections } } + /// <summary> + /// Wrapper around Godot's Dictionary class, a dictionary of Variant + /// typed elements allocated in the engine in C++. Useful when + /// interfacing with the engine. + /// </summary> public class Dictionary : IDictionary, IDisposable @@ -32,11 +38,19 @@ namespace Godot.Collections DictionarySafeHandle safeHandle; bool disposed = false; + /// <summary> + /// Constructs a new empty <see cref="Dictionary"/>. + /// </summary> public Dictionary() { safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor()); } + /// <summary> + /// Constructs a new <see cref="Dictionary"/> from the given dictionary's elements. + /// </summary> + /// <param name="dictionary">The dictionary to construct from.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary dictionary) : this() { if (dictionary == null) @@ -64,6 +78,9 @@ namespace Godot.Collections return safeHandle.DangerousGetHandle(); } + /// <summary> + /// Disposes of this <see cref="Dictionary"/>. + /// </summary> public void Dispose() { if (disposed) @@ -78,6 +95,11 @@ namespace Godot.Collections disposed = true; } + /// <summary> + /// Duplicates this <see cref="Dictionary"/>. + /// </summary> + /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary Duplicate(bool deep = false) { return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep)); @@ -85,6 +107,9 @@ namespace Godot.Collections // IDictionary + /// <summary> + /// Gets the collection of keys in this <see cref="Dictionary"/>. + /// </summary> public ICollection Keys { get @@ -94,6 +119,9 @@ namespace Godot.Collections } } + /// <summary> + /// Gets the collection of elements in this <see cref="Dictionary"/>. + /// </summary> public ICollection Values { get @@ -103,47 +131,88 @@ namespace Godot.Collections } } - public bool IsFixedSize => false; + private (Array keys, Array values, int count) GetKeyValuePairs() + { + int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle); + Array keys = new Array(new ArraySafeHandle(keysHandle)); + Array values = new Array(new ArraySafeHandle(valuesHandle)); + return (keys, values, count); + } + + bool IDictionary.IsFixedSize => false; - public bool IsReadOnly => false; + bool IDictionary.IsReadOnly => false; + /// <summary> + /// Returns the object at the given <paramref name="key"/>. + /// </summary> + /// <value>The object at the given <paramref name="key"/>.</value> public object this[object key] { get => godot_icall_Dictionary_GetValue(GetPtr(), key); set => godot_icall_Dictionary_SetValue(GetPtr(), key, value); } + /// <summary> + /// Adds an object <paramref name="value"/> at key <paramref name="key"/> + /// to this <see cref="Dictionary"/>. + /// </summary> + /// <param name="key">The key at which to add the object.</param> + /// <param name="value">The object to add.</param> public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value); + /// <summary> + /// Erases all items from this <see cref="Dictionary"/>. + /// </summary> public void Clear() => godot_icall_Dictionary_Clear(GetPtr()); + /// <summary> + /// Checks if this <see cref="Dictionary"/> contains the given key. + /// </summary> + /// <param name="key">The key to look for.</param> + /// <returns>Whether or not this dictionary contains the given key.</returns> public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key); + /// <summary> + /// Gets an enumerator for this <see cref="Dictionary"/>. + /// </summary> + /// <returns>An enumerator.</returns> public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this); + /// <summary> + /// Removes an element from this <see cref="Dictionary"/> by key. + /// </summary> + /// <param name="key">The key of the element to remove.</param> public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key); // ICollection - public object SyncRoot => this; + object ICollection.SyncRoot => this; - public bool IsSynchronized => false; + bool ICollection.IsSynchronized => false; + /// <summary> + /// Returns the number of elements in this <see cref="Dictionary"/>. + /// This is also known as the size or length of the dictionary. + /// </summary> + /// <returns>The number of elements.</returns> public int Count => godot_icall_Dictionary_Count(GetPtr()); + /// <summary> + /// Copies the elements of this <see cref="Dictionary"/> to the given + /// untyped C# array, starting at the given index. + /// </summary> + /// <param name="array">The array to copy to.</param> + /// <param name="index">The index to start at.</param> public void CopyTo(System.Array array, int index) { - // TODO Can be done with single internal call - if (array == null) throw new ArgumentNullException(nameof(array), "Value cannot be null."); if (index < 0) throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension."); - Array keys = (Array)Keys; - Array values = (Array)Values; - int count = Count; + var (keys, values, count) = GetKeyValuePairs(); if (array.Length < (index + count)) throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds."); @@ -161,24 +230,39 @@ namespace Godot.Collections private class DictionaryEnumerator : IDictionaryEnumerator { - Array keys; - Array values; - int count; - int index = -1; + private readonly Dictionary dictionary; + private readonly int count; + private int index = -1; + private bool dirty = true; + + private DictionaryEntry entry; public DictionaryEnumerator(Dictionary dictionary) { - // TODO 3 internal calls, can reduce to 1 - keys = (Array)dictionary.Keys; - values = (Array)dictionary.Values; + this.dictionary = dictionary; count = dictionary.Count; } public object Current => Entry; - public DictionaryEntry Entry => - // TODO 2 internal calls, can reduce to 1 - new DictionaryEntry(keys[index], values[index]); + public DictionaryEntry Entry + { + get + { + if (dirty) + { + UpdateEntry(); + } + return entry; + } + } + + private void UpdateEntry() + { + dirty = false; + godot_icall_Dictionary_KeyValuePairAt(dictionary.GetPtr(), index, out object key, out object value); + entry = new DictionaryEntry(key, value); + } public object Key => Entry.Key; @@ -187,15 +271,21 @@ namespace Godot.Collections public bool MoveNext() { index++; + dirty = true; return index < count; } public void Reset() { index = -1; + dirty = true; } } + /// <summary> + /// Converts this <see cref="Dictionary"/> to a string. + /// </summary> + /// <returns>A string representation of this dictionary.</returns> public override string ToString() { return godot_icall_Dictionary_ToString(GetPtr()); @@ -226,6 +316,12 @@ namespace Godot.Collections internal extern static int godot_icall_Dictionary_Count(IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal extern static void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value); + + [MethodImpl(MethodImplOptions.InternalCall)] internal extern static void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value); [MethodImpl(MethodImplOptions.InternalCall)] @@ -259,10 +355,18 @@ namespace Godot.Collections internal extern static string godot_icall_Dictionary_ToString(IntPtr ptr); } + /// <summary> + /// Typed wrapper around Godot's Dictionary class, a dictionary of Variant + /// typed elements allocated in the engine in C++. Useful when + /// interfacing with the engine. Otherwise prefer .NET collections + /// such as <see cref="System.Collections.Generic.Dictionary{TKey, TValue}"/>. + /// </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> : IDictionary<TKey, TValue> { - Dictionary objectDict; + private readonly Dictionary objectDict; internal static int valTypeEncoding; internal static IntPtr valTypeClass; @@ -272,11 +376,19 @@ namespace Godot.Collections Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass); } + /// <summary> + /// Constructs a new empty <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public Dictionary() { objectDict = new Dictionary(); } + /// <summary> + /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements. + /// </summary> + /// <param name="dictionary">The dictionary to construct from.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary(IDictionary<TKey, TValue> dictionary) { objectDict = new Dictionary(); @@ -294,6 +406,11 @@ namespace Godot.Collections } } + /// <summary> + /// Constructs a new <see cref="Dictionary{TKey, TValue}"/> from the given dictionary's elements. + /// </summary> + /// <param name="dictionary">The dictionary to construct from.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary(Dictionary dictionary) { objectDict = dictionary; @@ -309,6 +426,10 @@ namespace Godot.Collections objectDict = new Dictionary(handle); } + /// <summary> + /// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>. + /// </summary> + /// <param name="from">The typed dictionary to convert.</param> public static explicit operator Dictionary(Dictionary<TKey, TValue> from) { return from.objectDict; @@ -319,6 +440,11 @@ namespace Godot.Collections return objectDict.GetPtr(); } + /// <summary> + /// Duplicates this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + /// <param name="deep">If <see langword="true"/>, performs a deep copy.</param> + /// <returns>A new Godot Dictionary.</returns> public Dictionary<TKey, TValue> Duplicate(bool deep = false) { return new Dictionary<TKey, TValue>(objectDict.Duplicate(deep)); @@ -326,12 +452,19 @@ namespace Godot.Collections // IDictionary<TKey, TValue> + /// <summary> + /// Returns the value at the given <paramref name="key"/>. + /// </summary> + /// <value>The value at the given <paramref name="key"/>.</value> public TValue this[TKey key] { get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); } set { objectDict[key] = value; } } + /// <summary> + /// Gets the collection of keys in this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public ICollection<TKey> Keys { get @@ -341,6 +474,9 @@ namespace Godot.Collections } } + /// <summary> + /// Gets the collection of elements in this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public ICollection<TValue> Values { get @@ -350,56 +486,93 @@ namespace Godot.Collections } } + private KeyValuePair<TKey, TValue> GetKeyValuePair(int index) + { + Dictionary.godot_icall_Dictionary_KeyValuePairAt(GetPtr(), index, out object key, out object value); + return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value); + } + + /// <summary> + /// Adds an object <paramref name="value"/> at key <paramref name="key"/> + /// to this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + /// <param name="key">The key at which to add the object.</param> + /// <param name="value">The object to add.</param> public void Add(TKey key, TValue value) { objectDict.Add(key, value); } + /// <summary> + /// Checks if this <see cref="Dictionary{TKey, TValue}"/> contains the given key. + /// </summary> + /// <param name="key">The key to look for.</param> + /// <returns>Whether or not this dictionary contains the given key.</returns> public bool ContainsKey(TKey key) { return objectDict.Contains(key); } + /// <summary> + /// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key. + /// </summary> + /// <param name="key">The key of the element to remove.</param> public bool Remove(TKey key) { return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key); } - public bool TryGetValue(TKey key, out TValue value) + /// <summary> + /// Gets the object at the given <paramref name="key"/>. + /// </summary> + /// <param name="key">The key of the element to get.</param> + /// <param name="value">The value at the given <paramref name="key"/>.</param> + /// <returns>If an object was found for the given <paramref name="key"/>.</returns> + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { - object retValue; - bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out retValue, valTypeEncoding, valTypeClass); - value = found ? (TValue)retValue : default(TValue); + bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out object retValue, valTypeEncoding, valTypeClass); + value = found ? (TValue)retValue : default; return found; } // ICollection<KeyValuePair<TKey, TValue>> + /// <summary> + /// Returns the number of elements in this <see cref="Dictionary{TKey, TValue}"/>. + /// This is also known as the size or length of the dictionary. + /// </summary> + /// <returns>The number of elements.</returns> public int Count { get { return objectDict.Count; } } - public bool IsReadOnly - { - get { return objectDict.IsReadOnly; } - } + bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false; - public void Add(KeyValuePair<TKey, TValue> item) + void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) { objectDict.Add(item.Key, item.Value); } + /// <summary> + /// Erases all the items from this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> public void Clear() { objectDict.Clear(); } - public bool Contains(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) { return objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value)); } + /// <summary> + /// Copies the elements of this <see cref="Dictionary{TKey, TValue}"/> to the given + /// untyped C# array, starting at the given index. + /// </summary> + /// <param name="array">The array to copy to.</param> + /// <param name="arrayIndex">The index to start at.</param> public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { if (array == null) @@ -408,9 +581,6 @@ namespace Godot.Collections if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension."); - // TODO 3 internal calls, can reduce to 1 - Array<TKey> keys = (Array<TKey>)Keys; - Array<TValue> values = (Array<TValue>)Values; int count = Count; if (array.Length < (arrayIndex + count)) @@ -418,13 +588,12 @@ namespace Godot.Collections for (int i = 0; i < count; i++) { - // TODO 2 internal calls, can reduce to 1 - array[arrayIndex] = new KeyValuePair<TKey, TValue>(keys[i], values[i]); + array[arrayIndex] = GetKeyValuePair(i); arrayIndex++; } } - public bool Remove(KeyValuePair<TKey, TValue> item) + bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) { return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value); ; @@ -432,17 +601,15 @@ namespace Godot.Collections // IEnumerable<KeyValuePair<TKey, TValue>> + /// <summary> + /// Gets an enumerator for this <see cref="Dictionary{TKey, TValue}"/>. + /// </summary> + /// <returns>An enumerator.</returns> public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { - // TODO 3 internal calls, can reduce to 1 - Array<TKey> keys = (Array<TKey>)Keys; - Array<TValue> values = (Array<TValue>)Values; - int count = Count; - - for (int i = 0; i < count; i++) + for (int i = 0; i < Count; i++) { - // TODO 2 internal calls, can reduce to 1 - yield return new KeyValuePair<TKey, TValue>(keys[i], values[i]); + yield return GetKeyValuePair(i); } } @@ -451,6 +618,10 @@ namespace Godot.Collections return GetEnumerator(); } + /// <summary> + /// Converts this <see cref="Dictionary{TKey, TValue}"/> to a string. + /// </summary> + /// <returns>A string representation of this dictionary.</returns> public override string ToString() => objectDict.ToString(); } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs index a6f7a80d64..71d0593916 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs @@ -128,9 +128,9 @@ namespace Godot return godot_icall_GD_randi_range(from, to); } - public static uint RandSeed(ulong seed, out ulong newSeed) + public static uint RandFromSeed(ref ulong seed) { - return godot_icall_GD_rand_seed(seed, out newSeed); + return godot_icall_GD_rand_seed(seed, out seed); } public static IEnumerable<int> Range(int end) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index 1b717fb4ae..afc6a65a45 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -124,11 +124,11 @@ namespace Godot /* not sure if very "efficient" but good enough? */ Vector3 sourceScale = basis.Scale; - Quaternion sourceRotation = basis.RotationQuaternion(); + Quaternion sourceRotation = basis.GetRotationQuaternion(); Vector3 sourceLocation = origin; Vector3 destinationScale = transform.basis.Scale; - Quaternion destinationRotation = transform.basis.RotationQuaternion(); + Quaternion destinationRotation = transform.basis.GetRotationQuaternion(); Vector3 destinationLocation = transform.origin; var interpolated = new Transform3D(); diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp index 191f863350..86976de244 100644 --- a/modules/mono/glue/collections_glue.cpp +++ b/modules/mono/glue/collections_glue.cpp @@ -230,6 +230,19 @@ int32_t godot_icall_Dictionary_Count(Dictionary *ptr) { return ptr->size(); } +int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) { + *keys = godot_icall_Dictionary_Keys(ptr); + *values = godot_icall_Dictionary_Values(ptr); + return godot_icall_Dictionary_Count(ptr); +} + +void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) { + Array *keys = godot_icall_Dictionary_Keys(ptr); + Array *values = godot_icall_Dictionary_Values(ptr); + *key = GDMonoMarshal::variant_to_mono_object(keys->get(index)); + *value = GDMonoMarshal::variant_to_mono_object(values->get(index)); +} + void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) { Variant varKey = GDMonoMarshal::mono_object_to_variant(key); Variant *ret = ptr->getptr(varKey); @@ -338,6 +351,8 @@ void godot_register_collections_icalls() { GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs); + GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear); GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index fa4888f843..66816f32d1 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1161,7 +1161,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te return true; } -bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { +bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { _THREAD_SAFE_METHOD_ ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -1191,7 +1191,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con return true; } -bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) { +bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.getornull(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -1222,34 +1222,10 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->objects[key].rect.position.x = sd->width; sd->width += sd->objects[key].rect.size.x; - switch (sd->objects[key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); - } break; - } sd->glyphs.write[i].advance = sd->objects[key].rect.size.x; } else { sd->objects[key].rect.position.y = sd->width; sd->width += sd->objects[key].rect.size.y; - switch (sd->objects[key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); - } break; - } sd->glyphs.write[i].advance = sd->objects[key].rect.size.y; } } else { @@ -1279,35 +1255,71 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, } // Align embedded objects to baseline. + float full_ascent = sd->ascent; + float full_descent = sd->descent; for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.y = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.y = -(E->get().rect.size.y / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.y = (-sd->ascent + sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.y = 0; + } break; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.y = sd->descent; + } break; + } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.y -= E->get().rect.size.y; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.y -= E->get().rect.size.y / 2; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.y = sd->descent - E->get().rect.size.y; + case INLINE_ALIGN_TOP_TO: { + //NOP } break; } + full_ascent = MAX(full_ascent, -E->get().rect.position.y); + full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); } else { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.x = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.x = -(E->get().rect.size.x / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.x = (-sd->ascent + sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.x = 0; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.x = sd->descent - E->get().rect.size.x; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.x = sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.x -= E->get().rect.size.x; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.x -= E->get().rect.size.x / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.x); + full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); } } } + sd->ascent = full_ascent; + sd->descent = full_descent; } return true; } @@ -1404,33 +1416,9 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; - switch (new_sd->objects[key].inline_align) { - case VALIGN_TOP: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); - } break; - case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); - new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); - } break; - case VALIGN_BOTTOM: { - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); - } break; - } } else { new_sd->objects[key].rect.position.y = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.y; - switch (new_sd->objects[key].inline_align) { - case VALIGN_TOP: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); - } break; - case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); - new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); - } break; - case VALIGN_BOTTOM: { - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); - } break; - } } } else { if (prev_rid != gl.font_rid) { @@ -1464,37 +1452,72 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng } // Align embedded objects to baseline. + float full_ascent = new_sd->ascent; + float full_descent = new_sd->descent; for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) { if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.y = -new_sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.y = -(E->get().rect.size.y / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.y = 0; + } break; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.y = new_sd->descent; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.y = new_sd->descent - E->get().rect.size.y; + } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.y -= E->get().rect.size.y; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.y -= E->get().rect.size.y / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP } break; } + full_ascent = MAX(full_ascent, -E->get().rect.position.y); + full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); } else { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.x = -new_sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.x = -(E->get().rect.size.x / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.x = new_sd->descent - E->get().rect.size.x; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.x = 0; + } break; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.x = new_sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.x -= E->get().rect.size.x; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.x -= E->get().rect.size.x / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.x); + full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); } } } + new_sd->ascent = full_ascent; + new_sd->descent = full_descent; } - new_sd->valid = true; return shaped_owner.make_rid(new_sd); @@ -2473,33 +2496,9 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->objects[span.embedded_key].rect.position.x = sd->width; sd->width += sd->objects[span.embedded_key].rect.size.x; - switch (sd->objects[span.embedded_key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); - } break; - } } else { sd->objects[span.embedded_key].rect.position.y = sd->width; sd->width += sd->objects[span.embedded_key].rect.size.y; - switch (sd->objects[span.embedded_key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); - } break; - } } Glyph gl; gl.start = span.start; @@ -2539,34 +2538,69 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { } // Align embedded objects to baseline. + float full_ascent = sd->ascent; + float full_descent = sd->descent; for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.y = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.y = -(E->get().rect.size.y / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.y = (-sd->ascent + sd->descent) / 2; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.y = sd->descent - E->get().rect.size.y; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.y = 0; + } break; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.y = sd->descent; + } break; + } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.y -= E->get().rect.size.y; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.y -= E->get().rect.size.y / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP } break; } + full_ascent = MAX(full_ascent, -E->get().rect.position.y); + full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); } else { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.x = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.x = -(E->get().rect.size.x / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.x = (-sd->ascent + sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.x = 0; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.x = sd->descent - E->get().rect.size.x; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.x = sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.x -= E->get().rect.size.x; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.x -= E->get().rect.size.x / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.x); + full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); } } - + sd->ascent = full_ascent; + sd->descent = full_descent; sd->valid = true; return sd->valid; } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 3c4f840bfd..c54686c114 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -216,8 +216,8 @@ public: virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override; virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; virtual RID shaped_text_get_parent(RID p_shaped) const override; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 004cbc2bb3..b60bf8e8d3 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -661,7 +661,7 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te return true; } -bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { +bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.getornull(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -691,7 +691,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con return true; } -bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) { +bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { _THREAD_SAFE_METHOD_ ShapedTextData *sd = shaped_owner.getornull(p_shaped); ERR_FAIL_COND_V(!sd, false); @@ -724,34 +724,10 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->objects[key].rect.position.x = sd->width; sd->width += sd->objects[key].rect.size.x; - switch (sd->objects[key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y); - } break; - } sd->glyphs.write[i].advance = sd->objects[key].rect.size.x; } else { sd->objects[key].rect.position.y = sd->width; sd->width += sd->objects[key].rect.size.y; - switch (sd->objects[key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x); - } break; - } sd->glyphs.write[i].advance = sd->objects[key].rect.size.y; } } else { @@ -784,35 +760,71 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, } // Align embedded objects to baseline. + float full_ascent = sd->ascent; + float full_descent = sd->descent; for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.y = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.y = -(E->get().rect.size.y / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.y = (-sd->ascent + sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.y = 0; + } break; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.y = sd->descent; + } break; + } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.y -= E->get().rect.size.y; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.y -= E->get().rect.size.y / 2; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.y = sd->descent - E->get().rect.size.y; + case INLINE_ALIGN_TOP_TO: { + //NOP } break; } + full_ascent = MAX(full_ascent, -E->get().rect.position.y); + full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); } else { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.x = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.x = -(E->get().rect.size.x / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.x = (-sd->ascent + sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.x = 0; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.x = sd->descent - E->get().rect.size.x; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.x = sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.x -= E->get().rect.size.x; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.x -= E->get().rect.size.x / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.x); + full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); } } } + sd->ascent = full_ascent; + sd->descent = full_descent; } return true; } @@ -869,33 +881,9 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng if (new_sd->orientation == ORIENTATION_HORIZONTAL) { new_sd->objects[key].rect.position.x = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.x; - switch (new_sd->objects[key].inline_align) { - case VALIGN_TOP: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y); - } break; - case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2)); - new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2)); - } break; - case VALIGN_BOTTOM: { - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y); - } break; - } } else { new_sd->objects[key].rect.position.y = new_sd->width; new_sd->width += new_sd->objects[key].rect.size.y; - switch (new_sd->objects[key].inline_align) { - case VALIGN_TOP: { - new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x); - } break; - case VALIGN_CENTER: { - new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2)); - new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2)); - } break; - case VALIGN_BOTTOM: { - new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x); - } break; - } } } else { const FontDataFallback *fd = font_owner.getornull(gl.font_rid); @@ -923,35 +911,72 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng } } + // Align embedded objects to baseline. + float full_ascent = new_sd->ascent; + float full_descent = new_sd->descent; for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) { if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.y = -new_sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.y = -(E->get().rect.size.y / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.y = 0; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.y = new_sd->descent - E->get().rect.size.y; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.y = new_sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.y -= E->get().rect.size.y; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.y -= E->get().rect.size.y / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.y); + full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); } else { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.x = -new_sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.x = -(E->get().rect.size.x / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.x = 0; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.x = new_sd->descent - E->get().rect.size.x; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.x = new_sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.x -= E->get().rect.size.x; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.x -= E->get().rect.size.x / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.x); + full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); } } } + new_sd->ascent = full_ascent; + new_sd->descent = full_descent; } new_sd->valid = true; @@ -1336,33 +1361,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { if (sd->orientation == ORIENTATION_HORIZONTAL) { sd->objects[span.embedded_key].rect.position.x = sd->width; sd->width += sd->objects[span.embedded_key].rect.size.x; - switch (sd->objects[span.embedded_key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y); - } break; - } } else { sd->objects[span.embedded_key].rect.position.y = sd->width; sd->width += sd->objects[span.embedded_key].rect.size.y; - switch (sd->objects[span.embedded_key].inline_align) { - case VALIGN_TOP: { - sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x); - } break; - case VALIGN_CENTER: { - sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); - sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2)); - } break; - case VALIGN_BOTTOM: { - sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x); - } break; - } } Glyph gl; gl.start = span.start; @@ -1456,34 +1457,69 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { } // Align embedded objects to baseline. + float full_ascent = sd->ascent; + float full_descent = sd->descent; for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) { if (sd->orientation == ORIENTATION_HORIZONTAL) { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.y = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.y = -(E->get().rect.size.y / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.y = (-sd->ascent + sd->descent) / 2; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.y = sd->descent - E->get().rect.size.y; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.y = 0; + } break; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.y = sd->descent; + } break; + } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.y -= E->get().rect.size.y; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.y -= E->get().rect.size.y / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP } break; } + full_ascent = MAX(full_ascent, -E->get().rect.position.y); + full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y); } else { - switch (E->get().inline_align) { - case VALIGN_TOP: { + switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) { + case INLINE_ALIGN_TO_TOP: { E->get().rect.position.x = -sd->ascent; } break; - case VALIGN_CENTER: { - E->get().rect.position.x = -(E->get().rect.size.x / 2); + case INLINE_ALIGN_TO_CENTER: { + E->get().rect.position.x = (-sd->ascent + sd->descent) / 2; + } break; + case INLINE_ALIGN_TO_BASELINE: { + E->get().rect.position.x = 0; } break; - case VALIGN_BOTTOM: { - E->get().rect.position.x = sd->descent - E->get().rect.size.x; + case INLINE_ALIGN_TO_BOTTOM: { + E->get().rect.position.x = sd->descent; } break; } + switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) { + case INLINE_ALIGN_BOTTOM_TO: { + E->get().rect.position.x -= E->get().rect.size.x; + } break; + case INLINE_ALIGN_CENTER_TO: { + E->get().rect.position.x -= E->get().rect.size.x / 2; + } break; + case INLINE_ALIGN_TOP_TO: { + //NOP + } break; + } + full_ascent = MAX(full_ascent, -E->get().rect.position.x); + full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x); } } - + sd->ascent = full_ascent; + sd->descent = full_descent; sd->valid = true; return sd->valid; } diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index b70c8f4ec0..e3bbde76d4 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -165,8 +165,8 @@ public: virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override; virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; virtual RID shaped_text_get_parent(RID p_shaped) const override; diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp index 3d7aaee921..2b48e94604 100644 --- a/modules/vhacd/register_types.cpp +++ b/modules/vhacd/register_types.cpp @@ -33,7 +33,7 @@ #include "thirdparty/vhacd/public/VHACD.h" static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int p_max_convex_hulls = -1) { - Vector<float> vertices; + Vector<real_t> vertices; vertices.resize(p_faces.size() * 9); Vector<uint32_t> indices; indices.resize(p_faces.size() * 3); diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 9fa49b8a1d..cded1e587c 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -93,7 +93,7 @@ String VisualScriptYield::get_text() const { class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance { public: VisualScriptYield::YieldMode mode; - float wait_time; + double wait_time; virtual int get_working_memory_size() const { return 1; } //yield needs at least 1 //virtual bool is_output_port_unsequenced(int p_idx) const { return false; } @@ -159,7 +159,7 @@ VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() { return yield_mode; } -void VisualScriptYield::set_wait_time(float p_time) { +void VisualScriptYield::set_wait_time(double p_time) { if (wait_time == p_time) { return; } @@ -167,7 +167,7 @@ void VisualScriptYield::set_wait_time(float p_time) { ports_changed_notify(); } -float VisualScriptYield::get_wait_time() { +double VisualScriptYield::get_wait_time() { return wait_time; } diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index fa596173a6..6005ff30b0 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -47,7 +47,7 @@ public: private: YieldMode yield_mode; - float wait_time; + double wait_time; protected: virtual void _validate_property(PropertyInfo &property) const override; @@ -73,8 +73,8 @@ public: void set_yield_mode(YieldMode p_mode); YieldMode get_yield_mode(); - void set_wait_time(float p_time); - float get_wait_time(); + void set_wait_time(double p_time); + double get_wait_time(); virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp index 69822f6ff3..d7263dcf43 100644 --- a/modules/websocket/emws_peer.cpp +++ b/modules/websocket/emws_peer.cpp @@ -54,7 +54,7 @@ Error EMWSPeer::read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_strin } Error EMWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - ERR_FAIL_COND_V(_out_buf_size && (godot_js_websocket_buffered_amount(peer_sock) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); + ERR_FAIL_COND_V(_out_buf_size && ((uint64_t)godot_js_websocket_buffered_amount(peer_sock) >= (1ULL << _out_buf_size)), ERR_OUT_OF_MEMORY); int is_bin = write_mode == WebSocketPeer::WRITE_MODE_BINARY ? 1 : 0; diff --git a/platform/iphone/api/api.cpp b/platform/iphone/api/api.cpp new file mode 100644 index 0000000000..a23791fe1c --- /dev/null +++ b/platform/iphone/api/api.cpp @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* api.cpp */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ + +#include "api.h" + +#if defined(IPHONE_ENABLED) + +void register_iphone_api() { + godot_ios_plugins_initialize(); +} + +void unregister_iphone_api() { + godot_ios_plugins_deinitialize(); +} + +#else + +void register_iphone_api() {} +void unregister_iphone_api() {} + +#endif diff --git a/platform/iphone/api/api.h b/platform/iphone/api/api.h new file mode 100644 index 0000000000..c6570da7ec --- /dev/null +++ b/platform/iphone/api/api.h @@ -0,0 +1,42 @@ +/*************************************************************************/ +/* api.h */ +/*************************************************************************/ +/* 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 IPHONE_API_H +#define IPHONE_API_H + +#if defined(IPHONE_ENABLED) +extern void godot_ios_plugins_initialize(); +extern void godot_ios_plugins_deinitialize(); +#endif + +void register_iphone_api(); +void unregister_iphone_api(); + +#endif // IPHONE_API_H diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 8abc3b7ed5..248369369d 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -45,9 +45,6 @@ #include "platform/iphone/vulkan_context_iphone.h" #endif -extern void godot_ios_plugins_initialize(); -extern void godot_ios_plugins_deinitialize(); - class OSIPhone : public OS_Unix { private: static HashMap<String, void *> dynamic_symbol_lookup_table; diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index b69996ccf0..a999929cc4 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -145,8 +145,6 @@ void OSIPhone::deinitialize_modules() { if (ios) { memdelete(ios); } - - godot_ios_plugins_deinitialize(); } void OSIPhone::set_main_loop(MainLoop *p_main_loop) { @@ -183,8 +181,6 @@ bool OSIPhone::iterate() { } void OSIPhone::start() { - godot_ios_plugins_initialize(); - Main::start(); if (joypad_iphone) { diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 73aa013701..974f4d3018 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -318,8 +318,16 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); - Input::get_singleton()->set_mouse_position(wd.mouse_pos); + if (DS_OSX->mouse_mode == DisplayServer::MOUSE_MODE_CAPTURED) { + const NSRect contentRect = [wd.window_view frame]; + NSRect pointInWindowRect = NSMakeRect(contentRect.size.width / 2, contentRect.size.height / 2, 0, 0); + NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin; + CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y }; + CGWarpMouseCursorPosition(lMouseWarpPos); + } else { + _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]); + Input::get_singleton()->set_mouse_position(wd.mouse_pos); + } DS_OSX->window_focused = true; DS_OSX->_send_window_event(wd, DisplayServerOSX::WINDOW_EVENT_FOCUS_IN); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index e78b23c509..4be95487b8 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -2445,7 +2445,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } else { mb->set_button_index(MOUSE_BUTTON_WHEEL_DOWN); } - + mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } break; case WM_MOUSEHWHEEL: { mb->set_pressed(true); @@ -2456,11 +2456,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (motion < 0) { mb->set_button_index(MOUSE_BUTTON_WHEEL_LEFT); - mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } else { mb->set_button_index(MOUSE_BUTTON_WHEEL_RIGHT); - mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } + mb->set_factor(fabs((double)motion / (double)WHEEL_DELTA)); } break; case WM_XBUTTONDOWN: { mb->set_pressed(true); diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index da2ab6ada8..026f0a85a6 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -159,12 +159,12 @@ void AnimatedSprite2D::_notification(int p_what) { return; } - float speed = frames->get_animation_speed(animation) * speed_scale; + double speed = frames->get_animation_speed(animation) * speed_scale; if (speed == 0) { return; //do nothing } - float remaining = get_process_delta_time(); + double remaining = get_process_delta_time(); while (remaining) { if (timeout <= 0) { @@ -205,7 +205,7 @@ void AnimatedSprite2D::_notification(int p_what) { emit_signal(SceneStringNames::get_singleton()->frame_changed); } - float to_process = MIN(timeout, remaining); + double to_process = MIN(timeout, remaining); remaining -= to_process; timeout -= to_process; } @@ -310,8 +310,8 @@ int AnimatedSprite2D::get_frame() const { return frame; } -void AnimatedSprite2D::set_speed_scale(float p_speed_scale) { - float elapsed = _get_frame_duration() - timeout; +void AnimatedSprite2D::set_speed_scale(double p_speed_scale) { + double elapsed = _get_frame_duration() - timeout; speed_scale = MAX(p_speed_scale, 0.0f); @@ -320,7 +320,7 @@ void AnimatedSprite2D::set_speed_scale(float p_speed_scale) { timeout -= elapsed; } -float AnimatedSprite2D::get_speed_scale() const { +double AnimatedSprite2D::get_speed_scale() const { return speed_scale; } @@ -402,9 +402,9 @@ bool AnimatedSprite2D::is_playing() const { return playing; } -float AnimatedSprite2D::_get_frame_duration() { +double AnimatedSprite2D::_get_frame_duration() { if (frames.is_valid() && frames->has_animation(animation)) { - float speed = frames->get_animation_speed(animation) * speed_scale; + double speed = frames->get_animation_speed(animation) * speed_scale; if (speed > 0) { return 1.0 / speed; } diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index ef0027edf1..0769b19b50 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -56,7 +56,7 @@ class AnimatedSprite2D : public Node2D { void _res_changed(); - float _get_frame_duration(); + double _get_frame_duration(); void _reset_timeout(); void _set_playing(bool p_playing); bool _is_playing() const; @@ -94,8 +94,8 @@ public: void set_frame(int p_frame); int get_frame() const; - void set_speed_scale(float p_speed_scale); - float get_speed_scale() const; + void set_speed_scale(double p_speed_scale); + double get_speed_scale() const; void set_centered(bool p_center); bool is_centered() const; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index a341ba69ac..ced1c5cb81 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -65,7 +65,7 @@ void CPUParticles2D::set_amount(int p_amount) { particle_order.resize(p_amount); } -void CPUParticles2D::set_lifetime(float p_lifetime) { +void CPUParticles2D::set_lifetime(double p_lifetime) { ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; } @@ -74,7 +74,7 @@ void CPUParticles2D::set_one_shot(bool p_one_shot) { one_shot = p_one_shot; } -void CPUParticles2D::set_pre_process_time(float p_time) { +void CPUParticles2D::set_pre_process_time(double p_time) { pre_process_time = p_time; } @@ -86,7 +86,7 @@ void CPUParticles2D::set_randomness_ratio(real_t p_ratio) { randomness_ratio = p_ratio; } -void CPUParticles2D::set_lifetime_randomness(float p_random) { +void CPUParticles2D::set_lifetime_randomness(double p_random) { lifetime_randomness = p_random; } @@ -95,7 +95,7 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) { set_notify_transform(!p_enable); } -void CPUParticles2D::set_speed_scale(real_t p_scale) { +void CPUParticles2D::set_speed_scale(double p_scale) { speed_scale = p_scale; } @@ -107,7 +107,7 @@ int CPUParticles2D::get_amount() const { return particles.size(); } -float CPUParticles2D::get_lifetime() const { +double CPUParticles2D::get_lifetime() const { return lifetime; } @@ -115,7 +115,7 @@ bool CPUParticles2D::get_one_shot() const { return one_shot; } -float CPUParticles2D::get_pre_process_time() const { +double CPUParticles2D::get_pre_process_time() const { return pre_process_time; } @@ -127,7 +127,7 @@ real_t CPUParticles2D::get_randomness_ratio() const { return randomness_ratio; } -float CPUParticles2D::get_lifetime_randomness() const { +double CPUParticles2D::get_lifetime_randomness() const { return lifetime_randomness; } @@ -135,7 +135,7 @@ bool CPUParticles2D::get_use_local_coordinates() const { return local_coords; } -real_t CPUParticles2D::get_speed_scale() const { +double CPUParticles2D::get_speed_scale() const { return speed_scale; } @@ -516,7 +516,7 @@ void CPUParticles2D::_update_internal() { return; } - float delta = get_process_delta_time(); + double delta = get_process_delta_time(); if (emitting) { inactive_time = 0; } else { @@ -536,14 +536,14 @@ void CPUParticles2D::_update_internal() { _set_redraw(true); if (time == 0 && pre_process_time > 0.0) { - float frame_time; + double frame_time; if (fixed_fps > 0) { frame_time = 1.0 / fixed_fps; } else { frame_time = 1.0 / 30.0; } - float todo = pre_process_time; + double todo = pre_process_time; while (todo >= 0) { _particles_process(frame_time); @@ -552,16 +552,16 @@ void CPUParticles2D::_update_internal() { } if (fixed_fps > 0) { - float frame_time = 1.0 / fixed_fps; - float decr = frame_time; + double frame_time = 1.0 / fixed_fps; + double decr = frame_time; - float ldelta = delta; + double ldelta = delta; if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10 ldelta = 0.1; } else if (ldelta <= 0.0) { //unlikely but.. ldelta = 0.001; } - float todo = frame_remainder + ldelta; + double todo = frame_remainder + ldelta; while (todo >= frame_time) { _particles_process(frame_time); @@ -577,7 +577,7 @@ void CPUParticles2D::_update_internal() { _update_particle_data_buffer(); } -void CPUParticles2D::_particles_process(float p_delta) { +void CPUParticles2D::_particles_process(double p_delta) { p_delta *= speed_scale; int pcount = particles.size(); @@ -585,7 +585,7 @@ void CPUParticles2D::_particles_process(float p_delta) { Particle *parray = w; - float prev_time = time; + double prev_time = time; time += p_delta; if (time > lifetime) { time = Math::fmod(time, lifetime); @@ -604,7 +604,7 @@ void CPUParticles2D::_particles_process(float p_delta) { velocity_xform[2] = Vector2(); } - float system_phase = time / lifetime; + double system_phase = time / lifetime; for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -613,12 +613,12 @@ void CPUParticles2D::_particles_process(float p_delta) { continue; } - float local_delta = p_delta; + double local_delta = p_delta; // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. // While we use time in tests later on, for randomness we use the phase as done in the // original shader code, and we later multiply by lifetime to get the time. - real_t restart_phase = real_t(i) / real_t(pcount); + double restart_phase = double(i) / double(pcount); if (randomness_ratio > 0.0) { uint32_t seed = cycle; @@ -627,12 +627,12 @@ void CPUParticles2D::_particles_process(float p_delta) { } seed *= uint32_t(pcount); seed += uint32_t(i); - real_t random = (idhash(seed) % uint32_t(65536)) / 65536.0; - restart_phase += randomness_ratio * random * 1.0 / pcount; + double random = double(idhash(seed) % uint32_t(65536)) / 65536.0; + restart_phase += randomness_ratio * random * 1.0 / double(pcount); } restart_phase *= (1.0 - explosiveness_ratio); - float restart_time = restart_phase * lifetime; + double restart_time = restart_phase * lifetime; bool restart = false; if (time > prev_time) { @@ -874,7 +874,7 @@ void CPUParticles2D::_particles_process(float p_delta) { tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv); } - real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); + real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); real_t hue_rot_c = Math::cos(hue_rot_angle); real_t hue_rot_s = Math::sin(hue_rot_angle); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 92b8be77cf..1a1f35fca5 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -83,7 +83,7 @@ private: struct Particle { Transform2D transform; Color color; - float custom[4] = {}; + real_t custom[4] = {}; real_t rotation = 0.0; Vector2 velocity; bool active = false; @@ -91,16 +91,16 @@ private: real_t scale_rand = 0.0; real_t hue_rot_rand = 0.0; real_t anim_offset_rand = 0.0; - float time = 0.0; - float lifetime = 0.0; + double time = 0.0; + double lifetime = 0.0; Color base_color; uint32_t seed = 0; }; - float time = 0.0; - float inactive_time = 0.0; - float frame_remainder = 0.0; + double time = 0.0; + double inactive_time = 0.0; + double frame_remainder = 0.0; int cycle = 0; bool redraw = false; @@ -131,12 +131,12 @@ private: bool one_shot = false; - float lifetime = 1.0; - float pre_process_time = 0.0; + double lifetime = 1.0; + double pre_process_time = 0.0; real_t explosiveness_ratio = 0.0; real_t randomness_ratio = 0.0; - real_t lifetime_randomness = 0.0; - real_t speed_scale = 1.0; + double lifetime_randomness = 0.0; + double speed_scale = 1.0; bool local_coords; int fixed_fps = 0; bool fractional_delta = true; @@ -172,7 +172,7 @@ private: Vector2 gravity = Vector2(0, 980); void _update_internal(); - void _particles_process(float p_delta); + void _particles_process(double p_delta); void _update_particle_data_buffer(); Mutex update_mutex; @@ -193,27 +193,27 @@ protected: public: void set_emitting(bool p_emitting); void set_amount(int p_amount); - void set_lifetime(float p_lifetime); + void set_lifetime(double p_lifetime); void set_one_shot(bool p_one_shot); - void set_pre_process_time(float p_time); + void set_pre_process_time(double p_time); void set_explosiveness_ratio(real_t p_ratio); void set_randomness_ratio(real_t p_ratio); - void set_lifetime_randomness(float p_random); + void set_lifetime_randomness(double p_random); void set_visibility_aabb(const Rect2 &p_aabb); void set_use_local_coordinates(bool p_enable); - void set_speed_scale(real_t p_scale); + void set_speed_scale(double p_scale); bool is_emitting() const; int get_amount() const; - float get_lifetime() const; + double get_lifetime() const; bool get_one_shot() const; - float get_pre_process_time() const; + double get_pre_process_time() const; real_t get_explosiveness_ratio() const; real_t get_randomness_ratio() const; - float get_lifetime_randomness() const; + double get_lifetime_randomness() const; Rect2 get_visibility_aabb() const; bool get_use_local_coordinates() const; - real_t get_speed_scale() const; + double get_speed_scale() const; void set_fixed_fps(int p_count); int get_fixed_fps() const; diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index adfb94d574..4739d3dd46 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -54,7 +54,7 @@ void GPUParticles2D::set_amount(int p_amount) { RS::get_singleton()->particles_set_amount(particles, amount); } -void GPUParticles2D::set_lifetime(float p_lifetime) { +void GPUParticles2D::set_lifetime(double p_lifetime) { ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; RS::get_singleton()->particles_set_lifetime(particles, lifetime); @@ -76,7 +76,7 @@ void GPUParticles2D::set_one_shot(bool p_enable) { } } -void GPUParticles2D::set_pre_process_time(float p_time) { +void GPUParticles2D::set_pre_process_time(double p_time) { pre_process_time = p_time; RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time); } @@ -148,7 +148,8 @@ void GPUParticles2D::set_trail_enabled(bool p_enabled) { RS::get_singleton()->particles_set_transform_align(particles, p_enabled ? RS::PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY : RS::PARTICLES_TRANSFORM_ALIGN_DISABLED); } -void GPUParticles2D::set_trail_length(float p_seconds) { + +void GPUParticles2D::set_trail_length(double p_seconds) { ERR_FAIL_COND(p_seconds < 0.001); trail_length = p_seconds; RS::get_singleton()->particles_set_trails(particles, trail_enabled, trail_length); @@ -162,6 +163,7 @@ void GPUParticles2D::set_trail_sections(int p_sections) { trail_sections = p_sections; update(); } + void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) { ERR_FAIL_COND(trail_section_subdivisions < 1); ERR_FAIL_COND(trail_section_subdivisions > 1024); @@ -173,12 +175,13 @@ void GPUParticles2D::set_trail_section_subdivisions(int p_subdivisions) { bool GPUParticles2D::is_trail_enabled() const { return trail_enabled; } -float GPUParticles2D::get_trail_length() const { + +real_t GPUParticles2D::get_trail_length() const { return trail_length; } void GPUParticles2D::_update_collision_size() { - float csize = collision_base_size; + real_t csize = collision_base_size; if (texture.is_valid()) { csize *= (texture->get_width() + texture->get_height()) / 4.0; //half size since its a radius @@ -187,16 +190,16 @@ void GPUParticles2D::_update_collision_size() { RS::get_singleton()->particles_set_collision_base_size(particles, csize); } -void GPUParticles2D::set_collision_base_size(float p_size) { +void GPUParticles2D::set_collision_base_size(real_t p_size) { collision_base_size = p_size; _update_collision_size(); } -float GPUParticles2D::get_collision_base_size() const { +real_t GPUParticles2D::get_collision_base_size() const { return collision_base_size; } -void GPUParticles2D::set_speed_scale(float p_scale) { +void GPUParticles2D::set_speed_scale(double p_scale) { speed_scale = p_scale; RS::get_singleton()->particles_set_speed_scale(particles, p_scale); } @@ -209,7 +212,7 @@ int GPUParticles2D::get_amount() const { return amount; } -float GPUParticles2D::get_lifetime() const { +double GPUParticles2D::get_lifetime() const { return lifetime; } @@ -224,15 +227,15 @@ bool GPUParticles2D::get_one_shot() const { return one_shot; } -float GPUParticles2D::get_pre_process_time() const { +double GPUParticles2D::get_pre_process_time() const { return pre_process_time; } -float GPUParticles2D::get_explosiveness_ratio() const { +real_t GPUParticles2D::get_explosiveness_ratio() const { return explosiveness_ratio; } -float GPUParticles2D::get_randomness_ratio() const { +real_t GPUParticles2D::get_randomness_ratio() const { return randomness_ratio; } @@ -248,7 +251,7 @@ Ref<Material> GPUParticles2D::get_process_material() const { return process_material; } -float GPUParticles2D::get_speed_scale() const { +double GPUParticles2D::get_speed_scale() const { return speed_scale; } diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 9d8e61daf7..a80e52d60c 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -51,11 +51,11 @@ private: bool one_shot; int amount; - float lifetime; - float pre_process_time; + double lifetime; + double pre_process_time; float explosiveness_ratio; float randomness_ratio; - float speed_scale; + double speed_scale; Rect2 visibility_rect; bool local_coords; int fixed_fps; @@ -89,36 +89,36 @@ protected: public: void set_emitting(bool p_emitting); void set_amount(int p_amount); - void set_lifetime(float p_lifetime); + void set_lifetime(double p_lifetime); void set_one_shot(bool p_enable); - void set_pre_process_time(float p_time); + void set_pre_process_time(double p_time); void set_explosiveness_ratio(float p_ratio); void set_randomness_ratio(float p_ratio); void set_visibility_rect(const Rect2 &p_visibility_rect); void set_use_local_coordinates(bool p_enable); void set_process_material(const Ref<Material> &p_material); - void set_speed_scale(float p_scale); - void set_collision_base_size(float p_ratio); + void set_speed_scale(double p_scale); + void set_collision_base_size(real_t p_ratio); void set_trail_enabled(bool p_enabled); - void set_trail_length(float p_seconds); + void set_trail_length(double p_seconds); void set_trail_sections(int p_sections); void set_trail_section_subdivisions(int p_subdivisions); bool is_emitting() const; int get_amount() const; - float get_lifetime() const; + double get_lifetime() const; bool get_one_shot() const; - float get_pre_process_time() const; - float get_explosiveness_ratio() const; - float get_randomness_ratio() const; + double get_pre_process_time() const; + real_t get_explosiveness_ratio() const; + real_t get_randomness_ratio() const; Rect2 get_visibility_rect() const; bool get_use_local_coordinates() const; Ref<Material> get_process_material() const; - float get_speed_scale() const; + double get_speed_scale() const; - float get_collision_base_size() const; + real_t get_collision_base_size() const; bool is_trail_enabled() const; - float get_trail_length() const; + real_t get_trail_length() const; int get_trail_sections() const; int get_trail_section_subdivisions() const; diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index ea639ae3a3..58b20ccad0 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -455,7 +455,7 @@ void NavigationRegion2D::_notification(int p_what) { // Draw the region Transform2D xform = get_global_transform(); const NavigationServer2D *ns = NavigationServer2D::get_singleton(); - float radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0; + real_t radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0; for (int i = 0; i < ns->region_get_connections_count(region); i++) { // Two main points Vector2 a = ns->region_get_connection_pathway_start(region, i); @@ -465,7 +465,7 @@ void NavigationRegion2D::_notification(int p_what) { draw_line(a, b, doors_color); // Draw a circle to illustrate the margins. - float angle = (b - a).angle(); + real_t angle = (b - a).angle(); draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color); draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color); } diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index a382fb2f1e..9235a2290e 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1062,7 +1062,9 @@ void CharacterBody2D::move_and_slide() { //this approach makes sure there is less delay between the actual body velocity and the one we saved PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(on_floor_body); if (bs) { - current_floor_velocity = bs->get_linear_velocity(); + Transform2D gt = get_global_transform(); + Vector2 local_position = gt.elements[2] - bs->get_transform().elements[2]; + current_floor_velocity = bs->get_velocity_at_local_position(local_position); } } @@ -1073,7 +1075,7 @@ void CharacterBody2D::move_and_slide() { floor_normal = Vector2(); floor_velocity = Vector2(); - if (current_floor_velocity != Vector2()) { + if (current_floor_velocity != Vector2() && on_floor_body.is_valid()) { PhysicsServer2D::MotionResult floor_result; Set<RID> exclude; exclude.insert(on_floor_body); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 7a319aabc9..c20372fe75 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -292,6 +292,8 @@ private: Ref<KinematicCollision2D> _get_slide_collision(int p_bounce); + void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result); + bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result); void set_safe_margin(real_t p_margin); @@ -314,7 +316,6 @@ private: const Vector2 &get_up_direction() const; void set_up_direction(const Vector2 &p_up_direction); - void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result); protected: void _notification(int p_what); diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index f6740040c1..602a0f2115 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -212,17 +212,17 @@ void RayCast2D::_update_raycast_state() { void RayCast2D::_draw_debug_shape() { Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color(); if (!enabled) { - float g = draw_col.get_v(); + const float g = draw_col.get_v(); draw_col.r = g; draw_col.g = g; draw_col.b = g; } // Draw an arrow indicating where the RayCast is pointing to - const float max_arrow_size = 6; - const float line_width = 1.4; + const real_t max_arrow_size = 6; + const real_t line_width = 1.4; bool no_line = target_position.length() < line_width; - float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); + real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); if (no_line) { arrow_size = target_position.length(); diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 15cbdf535e..85d632af00 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -45,7 +45,7 @@ bool Bone2D::_set(const StringName &p_path, const Variant &p_value) { } else if (path.begins_with("length")) { set_length(p_value); } else if (path.begins_with("bone_angle")) { - set_bone_angle(Math::deg2rad(float(p_value))); + set_bone_angle(Math::deg2rad(real_t(p_value))); } else if (path.begins_with("default_length")) { set_length(p_value); } @@ -330,7 +330,7 @@ bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p rel = (p_other_bone->get_global_transform().get_origin() - get_global_transform().get_origin()); rel = rel.rotated(-get_global_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation } else { - float angle_to_use = get_rotation() + bone_angle; + real_t angle_to_use = get_rotation() + bone_angle; rel = Vector2(cos(angle_to_use), sin(angle_to_use)) * (length * MIN(get_global_scale().x, get_global_scale().y)); rel = rel.rotated(-get_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation } @@ -414,12 +414,12 @@ void Bone2D::apply_rest() { set_transform(rest); } -void Bone2D::set_default_length(float p_length) { +void Bone2D::set_default_length(real_t p_length) { WARN_DEPRECATED_MSG("set_default_length is deprecated. Please use set_length instead!"); set_length(p_length); } -float Bone2D::get_default_length() const { +real_t Bone2D::get_default_length() const { WARN_DEPRECATED_MSG("get_default_length is deprecated. Please use get_length instead!"); return get_length(); } @@ -485,7 +485,7 @@ bool Bone2D::get_autocalculate_length_and_angle() const { return autocalculate_length_and_angle; } -void Bone2D::set_length(float p_length) { +void Bone2D::set_length(real_t p_length) { length = p_length; #ifdef TOOLS_ENABLED @@ -493,11 +493,11 @@ void Bone2D::set_length(float p_length) { #endif // TOOLS_ENABLED } -float Bone2D::get_length() const { +real_t Bone2D::get_length() const { return length; } -void Bone2D::set_bone_angle(float p_angle) { +void Bone2D::set_bone_angle(real_t p_angle) { bone_angle = p_angle; #ifdef TOOLS_ENABLED @@ -505,7 +505,7 @@ void Bone2D::set_bone_angle(float p_angle) { #endif // TOOLS_ENABLED } -float Bone2D::get_bone_angle() const { +real_t Bone2D::get_bone_angle() const { return bone_angle; } @@ -690,7 +690,7 @@ RID Skeleton2D::get_skeleton() const { return skeleton; } -void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent) { +void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, real_t p_amount, bool p_persistent) { ERR_FAIL_INDEX_MSG(p_bone_idx, bones.size(), "Bone index is out of range!"); bones.write[p_bone_idx].local_pose_override = p_override; bones.write[p_bone_idx].local_pose_override_amount = p_amount; @@ -728,7 +728,7 @@ Ref<SkeletonModificationStack2D> Skeleton2D::get_modification_stack() const { return modification_stack; } -void Skeleton2D::execute_modifications(float p_delta, int p_execution_mode) { +void Skeleton2D::execute_modifications(real_t p_delta, int p_execution_mode) { if (!modification_stack.is_valid()) { return; } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 59bd711960..56fd0e8504 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -49,8 +49,8 @@ class Bone2D : public Node2D { Transform2D rest; bool autocalculate_length_and_angle = true; - float length = 16; - float bone_angle = 0; + real_t length = 16; + real_t bone_angle = 0; int skeleton_index = -1; @@ -85,10 +85,10 @@ public: void set_autocalculate_length_and_angle(bool p_autocalculate); bool get_autocalculate_length_and_angle() const; - void set_length(float p_length); - float get_length() const; - void set_bone_angle(float p_angle); - float get_bone_angle() const; + void set_length(real_t p_length); + real_t get_length() const; + void set_bone_angle(real_t p_angle); + real_t get_bone_angle() const; int get_index_in_skeleton() const; @@ -122,7 +122,7 @@ class Skeleton2D : public Node2D { //Transform2D local_pose_cache; Transform2D local_pose_override; - float local_pose_override_amount = 0; + real_t local_pose_override_amount = 0; bool local_pose_override_persistent = false; }; @@ -153,12 +153,12 @@ public: RID get_skeleton() const; - void set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent = true); + void set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, real_t p_amount, bool p_persistent = true); Transform2D get_bone_local_pose_override(int p_bone_idx); Ref<SkeletonModificationStack2D> get_modification_stack() const; void set_modification_stack(Ref<SkeletonModificationStack2D> p_stack); - void execute_modifications(float p_delta, int p_execution_mode); + void execute_modifications(real_t p_delta, int p_execution_mode); Skeleton2D(); ~Skeleton2D(); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 6afa0c0779..e2a415e5aa 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -1576,7 +1576,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c _make_quadrant_dirty(Q); } - used_size_cache_dirty = true; + used_rect_cache_dirty = true; } else { if (!E) { // Insert a new cell in the tile map. @@ -1604,7 +1604,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c c.alternative_tile = alternative_tile; _make_quadrant_dirty(Q); - used_size_cache_dirty = true; + used_rect_cache_dirty = true; } } @@ -1800,7 +1800,7 @@ void TileMap::clear_layer(int p_layer) { _clear_layer_internals(p_layer); layers[p_layer].tile_map.clear(); - used_size_cache_dirty = true; + used_rect_cache_dirty = true; } void TileMap::clear() { @@ -1809,7 +1809,7 @@ void TileMap::clear() { for (unsigned int i = 0; i < layers.size(); i++) { layers[i].tile_map.clear(); } - used_size_cache_dirty = true; + used_rect_cache_dirty = true; } void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) { @@ -2666,25 +2666,31 @@ TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const { Rect2 TileMap::get_used_rect() { // Not const because of cache // Return the rect of the currently used area - if (used_size_cache_dirty) { + if (used_rect_cache_dirty) { bool first = true; + used_rect_cache = Rect2i(); + for (unsigned int i = 0; i < layers.size(); i++) { const Map<Vector2i, TileMapCell> &tile_map = layers[i].tile_map; if (tile_map.size() > 0) { if (first) { - used_size_cache = Rect2(tile_map.front()->key().x, tile_map.front()->key().y, 1, 1); + used_rect_cache = Rect2i(tile_map.front()->key().x, tile_map.front()->key().y, 0, 0); first = false; } for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) { - used_size_cache.expand_to(Vector2(E->key().x + 1, E->key().y + 1)); + used_rect_cache.expand_to(Vector2i(E->key().x, E->key().y)); } } } - used_size_cache_dirty = false; + + if (!first) { // first is true if every layer is empty. + used_rect_cache.size += Vector2i(1, 1); // The cache expands to top-left coordinate, so we add one full tile. + } + used_rect_cache_dirty = false; } - return used_size_cache; + return used_rect_cache; } // --- Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems --- diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 4800780f94..dce18f7682 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -213,8 +213,8 @@ private: // Rect. Rect2 rect_cache; bool rect_cache_dirty = true; - Rect2 used_size_cache; - bool used_size_cache_dirty = true; + Rect2i used_rect_cache; + bool used_rect_cache_dirty = true; // TileMap layers. struct TileMapLayer { diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 2e962b96c3..e504277a55 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -153,7 +153,7 @@ Transform3D Camera3D::get_camera_transform() const { return tr; } -void Camera3D::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { +void Camera3D::set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far) { if (!force_change && fov == p_fovy_degrees && p_z_near == near && p_z_far == far && mode == PROJECTION_PERSPECTIVE) { return; } @@ -168,7 +168,7 @@ void Camera3D::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_f force_change = false; } -void Camera3D::set_orthogonal(float p_size, float p_z_near, float p_z_far) { +void Camera3D::set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far) { if (!force_change && size == p_size && p_z_near == near && p_z_far == far && mode == PROJECTION_ORTHOGONAL) { return; } @@ -184,7 +184,7 @@ void Camera3D::set_orthogonal(float p_size, float p_z_near, float p_z_far) { update_gizmos(); } -void Camera3D::set_frustum(float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { +void Camera3D::set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far) { if (!force_change && size == p_size && frustum_offset == p_offset && p_z_near == near && p_z_far == far && mode == PROJECTION_FRUSTUM) { return; } @@ -295,7 +295,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const { return get_camera_transform().origin; } else { Vector2 pos = cpos / viewport_size; - float vsize, hsize; + real_t vsize, hsize; if (keep_aspect == KEEP_WIDTH) { vsize = size / viewport_size.aspect(); hsize = size; @@ -368,7 +368,7 @@ Point2 Camera3D::unproject_position(const Vector3 &p_pos) const { return res; } -Vector3 Camera3D::project_position(const Point2 &p_point, float p_z_depth) const { +Vector3 Camera3D::project_position(const Point2 &p_point, real_t p_z_depth) const { ERR_FAIL_COND_V_MSG(!is_inside_tree(), Vector3(), "Camera is not inside scene."); if (p_z_depth == 0 && mode != PROJECTION_ORTHOGONAL) { @@ -531,15 +531,15 @@ void Camera3D::_bind_methods() { BIND_ENUM_CONSTANT(DOPPLER_TRACKING_PHYSICS_STEP); } -float Camera3D::get_fov() const { +real_t Camera3D::get_fov() const { return fov; } -float Camera3D::get_size() const { +real_t Camera3D::get_size() const { return size; } -float Camera3D::get_near() const { +real_t Camera3D::get_near() const { return near; } @@ -547,7 +547,7 @@ Vector2 Camera3D::get_frustum_offset() const { return frustum_offset; } -float Camera3D::get_far() const { +real_t Camera3D::get_far() const { return far; } @@ -555,19 +555,19 @@ Camera3D::Projection Camera3D::get_projection() const { return mode; } -void Camera3D::set_fov(float p_fov) { +void Camera3D::set_fov(real_t p_fov) { ERR_FAIL_COND(p_fov < 1 || p_fov > 179); fov = p_fov; _update_camera_mode(); } -void Camera3D::set_size(float p_size) { +void Camera3D::set_size(real_t p_size) { ERR_FAIL_COND(p_size < 0.1 || p_size > 16384); size = p_size; _update_camera_mode(); } -void Camera3D::set_near(float p_near) { +void Camera3D::set_near(real_t p_near) { near = p_near; _update_camera_mode(); } @@ -577,7 +577,7 @@ void Camera3D::set_frustum_offset(Vector2 p_offset) { _update_camera_mode(); } -void Camera3D::set_far(float p_far) { +void Camera3D::set_far(real_t p_far) { far = p_far; _update_camera_mode(); } @@ -630,21 +630,21 @@ bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const { return true; } -void Camera3D::set_v_offset(float p_offset) { +void Camera3D::set_v_offset(real_t p_offset) { v_offset = p_offset; _update_camera(); } -float Camera3D::get_v_offset() const { +real_t Camera3D::get_v_offset() const { return v_offset; } -void Camera3D::set_h_offset(float p_offset) { +void Camera3D::set_h_offset(real_t p_offset) { h_offset = p_offset; _update_camera(); } -float Camera3D::get_h_offset() const { +real_t Camera3D::get_h_offset() const { return h_offset; } @@ -672,11 +672,11 @@ Camera3D::~Camera3D() { //////////////////////////////////////// -void ClippedCamera3D::set_margin(float p_margin) { +void ClippedCamera3D::set_margin(real_t p_margin) { margin = p_margin; } -float ClippedCamera3D::get_margin() const { +real_t ClippedCamera3D::get_margin() const { return margin; } @@ -746,7 +746,7 @@ void ClippedCamera3D::_notification(int p_what) { xf.origin = ray_from; xf.orthonormalize(); - float closest_safe = 1.0f, closest_unsafe = 1.0f; + real_t closest_safe = 1.0f, closest_unsafe = 1.0f; if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) { clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe); } @@ -813,7 +813,7 @@ void ClippedCamera3D::clear_exceptions() { exclude.clear(); } -float ClippedCamera3D::get_clip_offset() const { +real_t ClippedCamera3D::get_clip_offset() const { return clip_offset; } diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index c6efc8f9a9..61e3f51d0b 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -63,13 +63,13 @@ private: Projection mode = PROJECTION_PERSPECTIVE; - float fov = 0.0; - float size = 1.0; + real_t fov = 0.0; + real_t size = 1.0; Vector2 frustum_offset; - float near = 0.0; - float far = 0.0; - float v_offset = 0.0; - float h_offset = 0.0; + real_t near = 0.0; + real_t far = 0.0; + real_t v_offset = 0.0; + real_t h_offset = 0.0; KeepAspect keep_aspect = KEEP_HEIGHT; RID camera; @@ -107,10 +107,9 @@ public: NOTIFICATION_LOST_CURRENT = 51 }; - void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); - void set_orthogonal(float p_size, float p_z_near, float p_z_far); - void set_frustum(float p_size, Vector2 p_offset, float p_z_near, - float p_z_far); + void set_perspective(real_t p_fovy_degrees, real_t p_z_near, real_t p_z_far); + void set_orthogonal(real_t p_size, real_t p_z_near, real_t p_z_far); + void set_frustum(real_t p_size, Vector2 p_offset, real_t p_z_near, real_t p_z_far); void set_projection(Camera3D::Projection p_mode); void make_current(); @@ -120,18 +119,18 @@ public: RID get_camera() const; - float get_fov() const; - float get_size() const; - float get_far() const; - float get_near() const; + real_t get_fov() const; + real_t get_size() const; + real_t get_far() const; + real_t get_near() const; Vector2 get_frustum_offset() const; Projection get_projection() const; - void set_fov(float p_fov); - void set_size(float p_size); - void set_far(float p_far); - void set_near(float p_near); + void set_fov(real_t p_fov); + void set_size(real_t p_size); + void set_far(real_t p_far); + void set_near(real_t p_near); void set_frustum_offset(Vector2 p_offset); virtual Transform3D get_camera_transform() const; @@ -141,8 +140,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const; virtual Point2 unproject_position(const Vector3 &p_pos) const; bool is_position_behind(const Vector3 &p_pos) const; - virtual Vector3 project_position(const Point2 &p_point, - float p_z_depth) const; + virtual Vector3 project_position(const Point2 &p_point, real_t p_z_depth) const; Vector<Vector3> get_near_plane_points() const; @@ -164,11 +162,11 @@ public: void set_keep_aspect_mode(KeepAspect p_aspect); KeepAspect get_keep_aspect_mode() const; - void set_v_offset(float p_offset); - float get_v_offset() const; + void set_v_offset(real_t p_offset); + real_t get_v_offset() const; - void set_h_offset(float p_offset); - float get_h_offset() const; + void set_h_offset(real_t p_offset); + real_t get_h_offset() const; void set_doppler_tracking(DopplerTracking p_tracking); DopplerTracking get_doppler_tracking() const; @@ -195,8 +193,8 @@ public: private: ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS; RID pyramid_shape; - float margin = 0.0; - float clip_offset = 0.0; + real_t margin = 0.0; + real_t clip_offset = 0.0; uint32_t collision_mask = 1; bool clip_to_areas = false; bool clip_to_bodies = true; @@ -217,8 +215,8 @@ public: void set_clip_to_bodies(bool p_clip); bool is_clip_to_bodies_enabled() const; - void set_margin(float p_margin); - float get_margin() const; + void set_margin(real_t p_margin); + real_t get_margin() const; void set_process_callback(ClipProcessCallback p_mode); ClipProcessCallback get_process_callback() const; @@ -235,7 +233,7 @@ public: void remove_exception(const Object *p_object); void clear_exceptions(); - float get_clip_offset() const; + real_t get_clip_offset() const; ClippedCamera3D(); ~ClippedCamera3D(); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 60f8ad8f36..2377c618aa 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -78,7 +78,7 @@ void CPUParticles3D::set_amount(int p_amount) { particle_order.resize(p_amount); } -void CPUParticles3D::set_lifetime(float p_lifetime) { +void CPUParticles3D::set_lifetime(double p_lifetime) { ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; } @@ -87,19 +87,19 @@ void CPUParticles3D::set_one_shot(bool p_one_shot) { one_shot = p_one_shot; } -void CPUParticles3D::set_pre_process_time(float p_time) { +void CPUParticles3D::set_pre_process_time(double p_time) { pre_process_time = p_time; } -void CPUParticles3D::set_explosiveness_ratio(float p_ratio) { +void CPUParticles3D::set_explosiveness_ratio(real_t p_ratio) { explosiveness_ratio = p_ratio; } -void CPUParticles3D::set_randomness_ratio(float p_ratio) { +void CPUParticles3D::set_randomness_ratio(real_t p_ratio) { randomness_ratio = p_ratio; } -void CPUParticles3D::set_lifetime_randomness(float p_random) { +void CPUParticles3D::set_lifetime_randomness(double p_random) { lifetime_randomness = p_random; } @@ -107,7 +107,7 @@ void CPUParticles3D::set_use_local_coordinates(bool p_enable) { local_coords = p_enable; } -void CPUParticles3D::set_speed_scale(float p_scale) { +void CPUParticles3D::set_speed_scale(double p_scale) { speed_scale = p_scale; } @@ -119,7 +119,7 @@ int CPUParticles3D::get_amount() const { return particles.size(); } -float CPUParticles3D::get_lifetime() const { +double CPUParticles3D::get_lifetime() const { return lifetime; } @@ -127,19 +127,19 @@ bool CPUParticles3D::get_one_shot() const { return one_shot; } -float CPUParticles3D::get_pre_process_time() const { +double CPUParticles3D::get_pre_process_time() const { return pre_process_time; } -float CPUParticles3D::get_explosiveness_ratio() const { +real_t CPUParticles3D::get_explosiveness_ratio() const { return explosiveness_ratio; } -float CPUParticles3D::get_randomness_ratio() const { +real_t CPUParticles3D::get_randomness_ratio() const { return randomness_ratio; } -float CPUParticles3D::get_lifetime_randomness() const { +double CPUParticles3D::get_lifetime_randomness() const { return lifetime_randomness; } @@ -147,7 +147,7 @@ bool CPUParticles3D::get_use_local_coordinates() const { return local_coords; } -float CPUParticles3D::get_speed_scale() const { +double CPUParticles3D::get_speed_scale() const { return speed_scale; } @@ -247,47 +247,47 @@ Vector3 CPUParticles3D::get_direction() const { return direction; } -void CPUParticles3D::set_spread(float p_spread) { +void CPUParticles3D::set_spread(real_t p_spread) { spread = p_spread; } -float CPUParticles3D::get_spread() const { +real_t CPUParticles3D::get_spread() const { return spread; } -void CPUParticles3D::set_flatness(float p_flatness) { +void CPUParticles3D::set_flatness(real_t p_flatness) { flatness = p_flatness; } -float CPUParticles3D::get_flatness() const { +real_t CPUParticles3D::get_flatness() const { return flatness; } -void CPUParticles3D::set_param(Parameter p_param, float p_value) { +void CPUParticles3D::set_param(Parameter p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); parameters[p_param] = p_value; } -float CPUParticles3D::get_param(Parameter p_param) const { +real_t CPUParticles3D::get_param(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return parameters[p_param]; } -void CPUParticles3D::set_param_randomness(Parameter p_param, float p_value) { +void CPUParticles3D::set_param_randomness(Parameter p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); randomness[p_param] = p_value; } -float CPUParticles3D::get_param_randomness(Parameter p_param) const { +real_t CPUParticles3D::get_param_randomness(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return randomness[p_param]; } -static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) { +static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) { Ref<Curve> curve = p_curve; if (!curve.is_valid()) { return; @@ -381,7 +381,7 @@ void CPUParticles3D::set_emission_shape(EmissionShape p_shape) { emission_shape = p_shape; } -void CPUParticles3D::set_emission_sphere_radius(float p_radius) { +void CPUParticles3D::set_emission_sphere_radius(real_t p_radius) { emission_sphere_radius = p_radius; } @@ -405,19 +405,19 @@ void CPUParticles3D::set_emission_ring_axis(Vector3 p_axis) { emission_ring_axis = p_axis; } -void CPUParticles3D::set_emission_ring_height(float p_height) { +void CPUParticles3D::set_emission_ring_height(real_t p_height) { emission_ring_height = p_height; } -void CPUParticles3D::set_emission_ring_radius(float p_radius) { +void CPUParticles3D::set_emission_ring_radius(real_t p_radius) { emission_ring_radius = p_radius; } -void CPUParticles3D::set_emission_ring_inner_radius(float p_radius) { +void CPUParticles3D::set_emission_ring_inner_radius(real_t p_radius) { emission_ring_inner_radius = p_radius; } -float CPUParticles3D::get_emission_sphere_radius() const { +real_t CPUParticles3D::get_emission_sphere_radius() const { return emission_sphere_radius; } @@ -441,15 +441,15 @@ Vector3 CPUParticles3D::get_emission_ring_axis() const { return emission_ring_axis; } -float CPUParticles3D::get_emission_ring_height() const { +real_t CPUParticles3D::get_emission_ring_height() const { return emission_ring_height; } -float CPUParticles3D::get_emission_ring_radius() const { +real_t CPUParticles3D::get_emission_ring_radius() const { return emission_ring_radius; } -float CPUParticles3D::get_emission_ring_inner_radius() const { +real_t CPUParticles3D::get_emission_ring_inner_radius() const { return emission_ring_inner_radius; } @@ -498,7 +498,7 @@ static uint32_t idhash(uint32_t x) { return x; } -static float rand_from_seed(uint32_t &seed) { +static real_t rand_from_seed(uint32_t &seed) { int k; int s = int(seed); if (s == 0) { @@ -510,7 +510,7 @@ static float rand_from_seed(uint32_t &seed) { s += 2147483647; } seed = uint32_t(s); - return float(seed % uint32_t(65536)) / 65535.0; + return (seed % uint32_t(65536)) / 65535.0; } void CPUParticles3D::_update_internal() { @@ -519,7 +519,7 @@ void CPUParticles3D::_update_internal() { return; } - float delta = get_process_delta_time(); + double delta = get_process_delta_time(); if (emitting) { inactive_time = 0; } else { @@ -541,14 +541,14 @@ void CPUParticles3D::_update_internal() { bool processed = false; if (time == 0 && pre_process_time > 0.0) { - float frame_time; + double frame_time; if (fixed_fps > 0) { frame_time = 1.0 / fixed_fps; } else { frame_time = 1.0 / 30.0; } - float todo = pre_process_time; + double todo = pre_process_time; while (todo >= 0) { _particles_process(frame_time); @@ -558,16 +558,16 @@ void CPUParticles3D::_update_internal() { } if (fixed_fps > 0) { - float frame_time = 1.0 / fixed_fps; - float decr = frame_time; + double frame_time = 1.0 / fixed_fps; + double decr = frame_time; - float ldelta = delta; + double ldelta = delta; if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10 ldelta = 0.1; } else if (ldelta <= 0.0) { //unlikely but.. ldelta = 0.001; } - float todo = frame_remainder + ldelta; + double todo = frame_remainder + ldelta; while (todo >= frame_time) { _particles_process(frame_time); @@ -587,7 +587,7 @@ void CPUParticles3D::_update_internal() { } } -void CPUParticles3D::_particles_process(float p_delta) { +void CPUParticles3D::_particles_process(double p_delta) { p_delta *= speed_scale; int pcount = particles.size(); @@ -595,7 +595,7 @@ void CPUParticles3D::_particles_process(float p_delta) { Particle *parray = w; - float prev_time = time; + double prev_time = time; time += p_delta; if (time > lifetime) { time = Math::fmod(time, lifetime); @@ -613,7 +613,7 @@ void CPUParticles3D::_particles_process(float p_delta) { velocity_xform = emission_xform.basis; } - float system_phase = time / lifetime; + double system_phase = time / lifetime; for (int i = 0; i < pcount; i++) { Particle &p = parray[i]; @@ -622,12 +622,12 @@ void CPUParticles3D::_particles_process(float p_delta) { continue; } - float local_delta = p_delta; + double local_delta = p_delta; // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. // While we use time in tests later on, for randomness we use the phase as done in the // original shader code, and we later multiply by lifetime to get the time. - float restart_phase = float(i) / float(pcount); + double restart_phase = double(i) / double(pcount); if (randomness_ratio > 0.0) { uint32_t seed = cycle; @@ -636,12 +636,12 @@ void CPUParticles3D::_particles_process(float p_delta) { } seed *= uint32_t(pcount); seed += uint32_t(i); - float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; - restart_phase += randomness_ratio * random * 1.0 / float(pcount); + double random = double(idhash(seed) % uint32_t(65536)) / 65536.0; + restart_phase += randomness_ratio * random * 1.0 / double(pcount); } restart_phase *= (1.0 - explosiveness_ratio); - float restart_time = restart_phase * lifetime; + double restart_time = restart_phase * lifetime; bool restart = false; if (time > prev_time) { @@ -682,17 +682,17 @@ void CPUParticles3D::_particles_process(float p_delta) { } p.active = true; - /*float tex_linear_velocity = 0; + /*real_t tex_linear_velocity = 0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0); }*/ - float tex_angle = 0.0; + real_t tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); } - float tex_anim_offset = 0.0; + real_t tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv); } @@ -705,26 +705,26 @@ void CPUParticles3D::_particles_process(float p_delta) { p.anim_offset_rand = Math::randf(); if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - float angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); + real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); - p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); + p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); } else { //initiate velocity spread in 3D - float angle1_rad = Math::atan2(direction.x, direction.z) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); - float angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * spread); + real_t angle1_rad = Math::atan2(direction.x, direction.z) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); + real_t angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * spread); Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad)); Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad)); direction_yz.z = direction_yz.z / MAX(0.0001, Math::sqrt(ABS(direction_yz.z))); //better uniform distribution Vector3 direction = Vector3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z); direction.normalize(); - p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); + p.velocity = direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); } - float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]); + real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]); p.custom[0] = Math::deg2rad(base_angle); //angle p.custom[1] = 0.0; //phase - p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1) + p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1) p.transform = Transform3D(); p.time = 0; p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness); @@ -783,8 +783,8 @@ void CPUParticles3D::_particles_process(float p_delta) { } } break; case EMISSION_SHAPE_RING: { - float ring_random_angle = Math::randf() * 2.0 * Math_PI; - float ring_random_radius = Math::randf() * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius; + real_t ring_random_angle = Math::randf() * Math_TAU; + real_t ring_random_radius = Math::randf() * (emission_ring_radius - emission_ring_inner_radius) + emission_ring_inner_radius; Vector3 axis = emission_ring_axis.normalized(); Vector3 ortho_axis = Vector3(); if (axis == Vector3(1.0, 0.0, 0.0)) { @@ -824,53 +824,53 @@ void CPUParticles3D::_particles_process(float p_delta) { p.custom[1] = p.time / lifetime; tv = p.time / p.lifetime; - float tex_linear_velocity = 0.0; + real_t tex_linear_velocity = 0.0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv); } - float tex_orbit_velocity = 0.0; + real_t tex_orbit_velocity = 0.0; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv); } } - float tex_angular_velocity = 0.0; + real_t tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv); } - float tex_linear_accel = 0.0; + real_t tex_linear_accel = 0.0; if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv); } - float tex_tangential_accel = 0.0; + real_t tex_tangential_accel = 0.0; if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv); } - float tex_radial_accel = 0.0; + real_t tex_radial_accel = 0.0; if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv); } - float tex_damping = 0.0; + real_t tex_damping = 0.0; if (curve_parameters[PARAM_DAMPING].is_valid()) { tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv); } - float tex_angle = 0.0; + real_t tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); } - float tex_anim_speed = 0.0; + real_t tex_anim_speed = 0.0; if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv); } - float tex_anim_offset = 0.0; + real_t tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv); } @@ -881,28 +881,28 @@ void CPUParticles3D::_particles_process(float p_delta) { position.z = 0.0; } //apply linear acceleration - force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3(); + force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3(); //apply radial acceleration Vector3 org = emission_xform.origin; Vector3 diff = position - org; - force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3(); + force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3(); //apply tangential acceleration; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { Vector2 yx = Vector2(diff.y, diff.x); Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized(); - force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); + force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); } else { Vector3 crossDiff = diff.normalized().cross(gravity.normalized()); - force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); + force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3(); } //apply attractor forces p.velocity += force * local_delta; //orbit velocity if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); + real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); if (orbit_amount != 0.0) { - float ang = orbit_amount * local_delta * Math_TAU; + real_t ang = orbit_amount * local_delta * Math_TAU; // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); @@ -915,8 +915,8 @@ void CPUParticles3D::_particles_process(float p_delta) { p.velocity = p.velocity.normalized() * tex_linear_velocity; } if (parameters[PARAM_DAMPING] + tex_damping > 0.0) { - float v = p.velocity.length(); - float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]); + real_t v = p.velocity.length(); + real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]); v -= damp * local_delta; if (v < 0.0) { p.velocity = Vector3(); @@ -924,27 +924,27 @@ void CPUParticles3D::_particles_process(float p_delta) { p.velocity = p.velocity.normalized() * v; } } - float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]); - base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]); + real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]); + base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]); p.custom[0] = Math::deg2rad(base_angle); //angle - p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle + p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle } //apply color //apply hue rotation - float tex_scale = 1.0; + real_t tex_scale = 1.0; if (curve_parameters[PARAM_SCALE].is_valid()) { tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv); } - float tex_hue_variation = 0.0; + real_t tex_hue_variation = 0.0; if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv); } - float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); - float hue_rot_c = Math::cos(hue_rot_angle); - float hue_rot_s = Math::sin(hue_rot_angle); + real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); + real_t hue_rot_c = Math::cos(hue_rot_angle); + real_t hue_rot_s = Math::sin(hue_rot_angle); Basis hue_rot_mat; { @@ -1013,9 +1013,9 @@ void CPUParticles3D::_particles_process(float p_delta) { } //scale by scale - float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]); - if (base_scale < 0.000001) { - base_scale = 0.000001; + real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]); + if (base_scale < CMP_EPSILON) { + base_scale = CMP_EPSILON; } p.transform.basis.scale(Vector3(1, 1, 1) * base_scale); @@ -1097,7 +1097,7 @@ void CPUParticles3D::_update_particle_data_buffer() { ptr[10] = t.basis.elements[2][2]; ptr[11] = t.origin.z; } else { - memset(ptr, 0, sizeof(float) * 12); + memset(ptr, 0, sizeof(Transform3D)); } Color c = r[idx].color; diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 07d345ba2c..bb6699ddc7 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -86,23 +86,23 @@ private: struct Particle { Transform3D transform; Color color; - float custom[4] = {}; + real_t custom[4] = {}; Vector3 velocity; bool active = false; - float angle_rand = 0.0; - float scale_rand = 0.0; - float hue_rot_rand = 0.0; - float anim_offset_rand = 0.0; - float time = 0.0; - float lifetime = 0.0; + real_t angle_rand = 0.0; + real_t scale_rand = 0.0; + real_t hue_rot_rand = 0.0; + real_t anim_offset_rand = 0.0; + double time = 0.0; + double lifetime = 0.0; Color base_color; uint32_t seed = 0; }; - float time = 0.0; - float inactive_time = 0.0; - float frame_remainder = 0.0; + double time = 0.0; + double inactive_time = 0.0; + double frame_remainder = 0.0; int cycle = 0; bool redraw = false; @@ -132,12 +132,12 @@ private: bool one_shot = false; - float lifetime = 1.0; - float pre_process_time = 0.0; - float explosiveness_ratio = 0.0; - float randomness_ratio = 0.0; - float lifetime_randomness = 0.0; - float speed_scale = 1.0; + double lifetime = 1.0; + double pre_process_time = 0.0; + real_t explosiveness_ratio = 0.0; + real_t randomness_ratio = 0.0; + double lifetime_randomness = 0.0; + double speed_scale = 1.0; bool local_coords = true; int fixed_fps = 0; bool fractional_delta = true; @@ -153,11 +153,11 @@ private: //////// Vector3 direction = Vector3(1, 0, 0); - float spread = 45.0; - float flatness = 0.0; + real_t spread = 45.0; + real_t flatness = 0.0; - float parameters[PARAM_MAX]; - float randomness[PARAM_MAX] = {}; + real_t parameters[PARAM_MAX]; + real_t randomness[PARAM_MAX] = {}; Ref<Curve> curve_parameters[PARAM_MAX]; Color color = Color(1, 1, 1, 1); @@ -166,21 +166,21 @@ private: bool particle_flags[PARTICLE_FLAG_MAX] = {}; EmissionShape emission_shape = EMISSION_SHAPE_POINT; - float emission_sphere_radius = 1.0; + real_t emission_sphere_radius = 1.0; Vector3 emission_box_extents = Vector3(1, 1, 1); Vector<Vector3> emission_points; Vector<Vector3> emission_normals; Vector<Color> emission_colors; int emission_point_count = 0; Vector3 emission_ring_axis; - float emission_ring_height; - float emission_ring_radius; - float emission_ring_inner_radius; + real_t emission_ring_height; + real_t emission_ring_radius; + real_t emission_ring_inner_radius; Vector3 gravity = Vector3(0, -9.8, 0); void _update_internal(); - void _particles_process(float p_delta); + void _particles_process(double p_delta); void _update_particle_data_buffer(); Mutex update_mutex; @@ -200,27 +200,27 @@ public: void set_emitting(bool p_emitting); void set_amount(int p_amount); - void set_lifetime(float p_lifetime); + void set_lifetime(double p_lifetime); void set_one_shot(bool p_one_shot); - void set_pre_process_time(float p_time); - void set_explosiveness_ratio(float p_ratio); - void set_randomness_ratio(float p_ratio); - void set_lifetime_randomness(float p_random); + void set_pre_process_time(double p_time); + void set_explosiveness_ratio(real_t p_ratio); + void set_randomness_ratio(real_t p_ratio); + void set_lifetime_randomness(double p_random); void set_visibility_aabb(const AABB &p_aabb); void set_use_local_coordinates(bool p_enable); - void set_speed_scale(float p_scale); + void set_speed_scale(double p_scale); bool is_emitting() const; int get_amount() const; - float get_lifetime() const; + double get_lifetime() const; bool get_one_shot() const; - float get_pre_process_time() const; - float get_explosiveness_ratio() const; - float get_randomness_ratio() const; - float get_lifetime_randomness() const; + double get_pre_process_time() const; + real_t get_explosiveness_ratio() const; + real_t get_randomness_ratio() const; + double get_lifetime_randomness() const; AABB get_visibility_aabb() const; bool get_use_local_coordinates() const; - float get_speed_scale() const; + double get_speed_scale() const; void set_fixed_fps(int p_count); int get_fixed_fps() const; @@ -242,17 +242,17 @@ public: void set_direction(Vector3 p_direction); Vector3 get_direction() const; - void set_spread(float p_spread); - float get_spread() const; + void set_spread(real_t p_spread); + real_t get_spread() const; - void set_flatness(float p_flatness); - float get_flatness() const; + void set_flatness(real_t p_flatness); + real_t get_flatness() const; - void set_param(Parameter p_param, float p_value); - float get_param(Parameter p_param) const; + void set_param(Parameter p_param, real_t p_value); + real_t get_param(Parameter p_param) const; - void set_param_randomness(Parameter p_param, float p_value); - float get_param_randomness(Parameter p_param) const; + void set_param_randomness(Parameter p_param, real_t p_value); + real_t get_param_randomness(Parameter p_param) const; void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve); Ref<Curve> get_param_curve(Parameter p_param) const; @@ -267,28 +267,28 @@ public: bool get_particle_flag(ParticleFlags p_particle_flag) const; void set_emission_shape(EmissionShape p_shape); - void set_emission_sphere_radius(float p_radius); + void set_emission_sphere_radius(real_t p_radius); void set_emission_box_extents(Vector3 p_extents); void set_emission_points(const Vector<Vector3> &p_points); void set_emission_normals(const Vector<Vector3> &p_normals); void set_emission_colors(const Vector<Color> &p_colors); void set_emission_point_count(int p_count); void set_emission_ring_axis(Vector3 p_axis); - void set_emission_ring_height(float p_height); - void set_emission_ring_radius(float p_radius); - void set_emission_ring_inner_radius(float p_radius); + void set_emission_ring_height(real_t p_height); + void set_emission_ring_radius(real_t p_radius); + void set_emission_ring_inner_radius(real_t p_radius); EmissionShape get_emission_shape() const; - float get_emission_sphere_radius() const; + real_t get_emission_sphere_radius() const; Vector3 get_emission_box_extents() const; Vector<Vector3> get_emission_points() const; Vector<Vector3> get_emission_normals() const; Vector<Color> get_emission_colors() const; int get_emission_point_count() const; Vector3 get_emission_ring_axis() const; - float get_emission_ring_height() const; - float get_emission_ring_radius() const; - float get_emission_ring_inner_radius() const; + real_t get_emission_ring_height() const; + real_t get_emission_ring_radius() const; + real_t get_emission_ring_inner_radius() const; void set_gravity(const Vector3 &p_gravity); Vector3 get_gravity() const; diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index 05f023721b..c94a99a203 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -53,48 +53,48 @@ Ref<Texture2D> Decal::get_texture(DecalTexture p_type) const { return textures[p_type]; } -void Decal::set_emission_energy(float p_energy) { +void Decal::set_emission_energy(real_t p_energy) { emission_energy = p_energy; RS::get_singleton()->decal_set_emission_energy(decal, emission_energy); } -float Decal::get_emission_energy() const { +real_t Decal::get_emission_energy() const { return emission_energy; } -void Decal::set_albedo_mix(float p_mix) { +void Decal::set_albedo_mix(real_t p_mix) { albedo_mix = p_mix; RS::get_singleton()->decal_set_albedo_mix(decal, albedo_mix); } -float Decal::get_albedo_mix() const { +real_t Decal::get_albedo_mix() const { return albedo_mix; } -void Decal::set_upper_fade(float p_fade) { +void Decal::set_upper_fade(real_t p_fade) { upper_fade = p_fade; RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade); } -float Decal::get_upper_fade() const { +real_t Decal::get_upper_fade() const { return upper_fade; } -void Decal::set_lower_fade(float p_fade) { +void Decal::set_lower_fade(real_t p_fade) { lower_fade = p_fade; RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade); } -float Decal::get_lower_fade() const { +real_t Decal::get_lower_fade() const { return lower_fade; } -void Decal::set_normal_fade(float p_fade) { +void Decal::set_normal_fade(real_t p_fade) { normal_fade = p_fade; RS::get_singleton()->decal_set_normal_fade(decal, normal_fade); } -float Decal::get_normal_fade() const { +real_t Decal::get_normal_fade() const { return normal_fade; } @@ -117,21 +117,21 @@ bool Decal::is_distance_fade_enabled() const { return distance_fade_enabled; } -void Decal::set_distance_fade_begin(float p_distance) { +void Decal::set_distance_fade_begin(real_t p_distance) { distance_fade_begin = p_distance; RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length); } -float Decal::get_distance_fade_begin() const { +real_t Decal::get_distance_fade_begin() const { return distance_fade_begin; } -void Decal::set_distance_fade_length(float p_length) { +void Decal::set_distance_fade_length(real_t p_length) { distance_fade_length = p_length; RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length); } -float Decal::get_distance_fade_length() const { +real_t Decal::get_distance_fade_length() const { return distance_fade_length; } diff --git a/scene/3d/decal.h b/scene/3d/decal.h index 31a6315213..041c8f97b2 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -51,16 +51,16 @@ private: RID decal; Vector3 extents = Vector3(1, 1, 1); Ref<Texture2D> textures[TEXTURE_MAX]; - float emission_energy = 1.0; - float albedo_mix = 1.0; + real_t emission_energy = 1.0; + real_t albedo_mix = 1.0; Color modulate = Color(1, 1, 1, 1); uint32_t cull_mask = (1 << 20) - 1; - float normal_fade = 0.0; - float upper_fade = 0.3; - float lower_fade = 0.3; + real_t normal_fade = 0.0; + real_t upper_fade = 0.3; + real_t lower_fade = 0.3; bool distance_fade_enabled = false; - float distance_fade_begin = 10.0; - float distance_fade_length = 1.0; + real_t distance_fade_begin = 10.0; + real_t distance_fade_length = 1.0; protected: static void _bind_methods(); @@ -75,32 +75,32 @@ public: void set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture(DecalTexture p_type) const; - void set_emission_energy(float p_energy); - float get_emission_energy() const; + void set_emission_energy(real_t p_energy); + real_t get_emission_energy() const; - void set_albedo_mix(float p_mix); - float get_albedo_mix() const; + void set_albedo_mix(real_t p_mix); + real_t get_albedo_mix() const; void set_modulate(Color p_modulate); Color get_modulate() const; - void set_upper_fade(float p_energy); - float get_upper_fade() const; + void set_upper_fade(real_t p_energy); + real_t get_upper_fade() const; - void set_lower_fade(float p_fade); - float get_lower_fade() const; + void set_lower_fade(real_t p_fade); + real_t get_lower_fade() const; - void set_normal_fade(float p_fade); - float get_normal_fade() const; + void set_normal_fade(real_t p_fade); + real_t get_normal_fade() const; void set_enable_distance_fade(bool p_enable); bool is_distance_fade_enabled() const; - void set_distance_fade_begin(float p_distance); - float get_distance_fade_begin() const; + void set_distance_fade_begin(real_t p_distance); + real_t get_distance_fade_begin() const; - void set_distance_fade_length(float p_length); - float get_distance_fade_length() const; + void set_distance_fade_length(real_t p_length); + real_t get_distance_fade_length() const; void set_cull_mask(uint32_t p_layers); uint32_t get_cull_mask() const; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 44cd7c10d8..8b8b53c3bf 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -59,7 +59,7 @@ void GPUParticles3D::set_amount(int p_amount) { RS::get_singleton()->particles_set_amount(particles, amount); } -void GPUParticles3D::set_lifetime(float p_lifetime) { +void GPUParticles3D::set_lifetime(double p_lifetime) { ERR_FAIL_COND_MSG(p_lifetime <= 0, "Particles lifetime must be greater than 0."); lifetime = p_lifetime; RS::get_singleton()->particles_set_lifetime(particles, lifetime); @@ -81,7 +81,7 @@ void GPUParticles3D::set_one_shot(bool p_one_shot) { } } -void GPUParticles3D::set_pre_process_time(float p_time) { +void GPUParticles3D::set_pre_process_time(double p_time) { pre_process_time = p_time; RS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time); } @@ -118,7 +118,7 @@ void GPUParticles3D::set_process_material(const Ref<Material> &p_material) { update_configuration_warnings(); } -void GPUParticles3D::set_speed_scale(float p_scale) { +void GPUParticles3D::set_speed_scale(double p_scale) { speed_scale = p_scale; RS::get_singleton()->particles_set_speed_scale(particles, p_scale); } @@ -136,7 +136,7 @@ int GPUParticles3D::get_amount() const { return amount; } -float GPUParticles3D::get_lifetime() const { +double GPUParticles3D::get_lifetime() const { return lifetime; } @@ -144,7 +144,7 @@ bool GPUParticles3D::get_one_shot() const { return one_shot; } -float GPUParticles3D::get_pre_process_time() const { +double GPUParticles3D::get_pre_process_time() const { return pre_process_time; } @@ -168,7 +168,7 @@ Ref<Material> GPUParticles3D::get_process_material() const { return process_material; } -float GPUParticles3D::get_speed_scale() const { +double GPUParticles3D::get_speed_scale() const { return speed_scale; } diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 7b21cf03f1..31e0e2abf5 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -64,11 +64,11 @@ private: bool one_shot; int amount; - float lifetime; - float pre_process_time; + double lifetime; + double pre_process_time; float explosiveness_ratio; float randomness_ratio; - float speed_scale; + double speed_scale; AABB visibility_aabb; bool local_coords; int fixed_fps; @@ -104,30 +104,30 @@ public: void set_emitting(bool p_emitting); void set_amount(int p_amount); - void set_lifetime(float p_lifetime); + void set_lifetime(double p_lifetime); void set_one_shot(bool p_one_shot); - void set_pre_process_time(float p_time); + void set_pre_process_time(double p_time); void set_explosiveness_ratio(float p_ratio); void set_randomness_ratio(float p_ratio); void set_visibility_aabb(const AABB &p_aabb); void set_use_local_coordinates(bool p_enable); void set_process_material(const Ref<Material> &p_material); - void set_speed_scale(float p_scale); + void set_speed_scale(double p_scale); void set_collision_base_size(float p_ratio); void set_trail_enabled(bool p_enabled); void set_trail_length(float p_seconds); bool is_emitting() const; int get_amount() const; - float get_lifetime() const; + double get_lifetime() const; bool get_one_shot() const; - float get_pre_process_time() const; + double get_pre_process_time() const; float get_explosiveness_ratio() const; float get_randomness_ratio() const; AABB get_visibility_aabb() const; bool get_use_local_coordinates() const; Ref<Material> get_process_material() const; - float get_speed_scale() const; + double get_speed_scale() const; float get_collision_base_size() const; bool is_trail_enabled() const; float get_trail_length() const; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index c2943a9606..40f33dfa72 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -38,7 +38,7 @@ bool Light3D::_can_gizmo_scale() const { return false; } -void Light3D::set_param(Param p_param, float p_value) { +void Light3D::set_param(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); param[p_param] = p_value; @@ -53,7 +53,7 @@ void Light3D::set_param(Param p_param, float p_value) { } } -float Light3D::get_param(Param p_param) const { +real_t Light3D::get_param(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return param[p_param]; } @@ -128,8 +128,8 @@ AABB Light3D::get_aabb() const { return AABB(Vector3(-1, -1, -1) * param[PARAM_RANGE], Vector3(2, 2, 2) * param[PARAM_RANGE]); } else if (type == RenderingServer::LIGHT_SPOT) { - float len = param[PARAM_RANGE]; - float size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len; + real_t len = param[PARAM_RANGE]; + real_t size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); } diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index d0308a3025..51ed2fcf50 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -71,7 +71,7 @@ public: private: Color color; - float param[PARAM_MAX] = {}; + real_t param[PARAM_MAX] = {}; Color shadow_color; bool shadow = false; bool negative = false; @@ -102,8 +102,8 @@ public: void set_editor_only(bool p_editor_only); bool is_editor_only() const; - void set_param(Param p_param, float p_value); - float get_param(Param p_param) const; + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; void set_shadow(bool p_enable); bool has_shadow() const; diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 0daee69ee5..8f186199db 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -588,31 +588,31 @@ bool Node3D::is_visible() const { return data.visible; } -void Node3D::rotate_object_local(const Vector3 &p_axis, float p_angle) { +void Node3D::rotate_object_local(const Vector3 &p_axis, real_t p_angle) { Transform3D t = get_transform(); t.basis.rotate_local(p_axis, p_angle); set_transform(t); } -void Node3D::rotate(const Vector3 &p_axis, float p_angle) { +void Node3D::rotate(const Vector3 &p_axis, real_t p_angle) { Transform3D t = get_transform(); t.basis.rotate(p_axis, p_angle); set_transform(t); } -void Node3D::rotate_x(float p_angle) { +void Node3D::rotate_x(real_t p_angle) { Transform3D t = get_transform(); t.basis.rotate(Vector3(1, 0, 0), p_angle); set_transform(t); } -void Node3D::rotate_y(float p_angle) { +void Node3D::rotate_y(real_t p_angle) { Transform3D t = get_transform(); t.basis.rotate(Vector3(0, 1, 0), p_angle); set_transform(t); } -void Node3D::rotate_z(float p_angle) { +void Node3D::rotate_z(real_t p_angle) { Transform3D t = get_transform(); t.basis.rotate(Vector3(0, 0, 1), p_angle); set_transform(t); @@ -644,7 +644,7 @@ void Node3D::scale_object_local(const Vector3 &p_scale) { set_transform(t); } -void Node3D::global_rotate(const Vector3 &p_axis, float p_angle) { +void Node3D::global_rotate(const Vector3 &p_axis, real_t p_angle) { Transform3D t = get_global_transform(); t.basis.rotate(p_axis, p_angle); set_global_transform(t); @@ -673,19 +673,17 @@ void Node3D::set_identity() { } void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) { - Vector3 origin(get_global_transform().origin); + Vector3 origin = get_global_transform().origin; look_at_from_position(origin, p_target, p_up); } void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) { - ERR_FAIL_COND_MSG(p_pos == p_target, "Node origin and target are in the same position, look_at() failed."); - ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos) == Vector3(), "Up vector and direction between node origin and target are aligned, look_at() failed."); + ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed."); + ERR_FAIL_COND_MSG(p_up.is_equal_approx(Vector3()), "The up vector can't be zero, look_at() failed."); + ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_equal_approx(Vector3()), "Up vector and direction between node origin and target are aligned, look_at() failed."); - Transform3D lookat; - lookat.origin = p_pos; - - Vector3 original_scale(get_scale()); - lookat = lookat.looking_at(p_target, p_up); + Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos); + Vector3 original_scale = get_scale(); set_global_transform(lookat); set_scale(original_scale); } diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 282f4805cc..da54452abb 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -167,18 +167,18 @@ public: Transform3D get_relative_transform(const Node *p_parent) const; - void rotate(const Vector3 &p_axis, float p_angle); - void rotate_x(float p_angle); - void rotate_y(float p_angle); - void rotate_z(float p_angle); + void rotate(const Vector3 &p_axis, real_t p_angle); + void rotate_x(real_t p_angle); + void rotate_y(real_t p_angle); + void rotate_z(real_t p_angle); void translate(const Vector3 &p_offset); void scale(const Vector3 &p_ratio); - void rotate_object_local(const Vector3 &p_axis, float p_angle); + void rotate_object_local(const Vector3 &p_axis, real_t p_angle); void scale_object_local(const Vector3 &p_scale); void translate_object_local(const Vector3 &p_offset); - void global_rotate(const Vector3 &p_axis, float p_angle); + void global_rotate(const Vector3 &p_axis, real_t p_angle); void global_scale(const Vector3 &p_scale); void global_translate(const Vector3 &p_offset); diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 490cf5fe67..6818acf69d 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -94,13 +94,13 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { return; } - float bl = c->get_baked_length(); + real_t bl = c->get_baked_length(); if (bl == 0.0) { return; } - float bi = c->get_bake_interval(); - float o_next = offset + bi; - float o_prev = offset - bi; + real_t bi = c->get_bake_interval(); + real_t o_next = offset + bi; + real_t o_prev = offset - bi; if (loop) { o_next = Math::fposmod(o_next, bl); @@ -120,7 +120,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used if (rotation_mode == ROTATION_ORIENTED) { - Vector3 forward = c->interpolate_baked(o_next, cubic); + Vector3 forward = c->interpolate_baked(o_next, cubic) - pos; // Try with the previous position if (forward.length_squared() < CMP_EPSILON2) { @@ -169,8 +169,8 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { Vector3 t_cur = (c->interpolate_baked(offset + delta_offset, cubic) - pos).normalized(); Vector3 axis = t_prev.cross(t_cur); - float dot = t_prev.dot(t_cur); - float angle = Math::acos(CLAMP(dot, -1, 1)); + real_t dot = t_prev.dot(t_cur); + real_t angle = Math::acos(CLAMP(dot, -1, 1)); if (likely(!Math::is_zero_approx(angle))) { if (rotation_mode == ROTATION_Y) { @@ -189,7 +189,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { } // do the additional tilting - float tilt_angle = c->interpolate_baked_tilt(offset); + real_t tilt_angle = c->interpolate_baked_tilt(offset); 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)))) { @@ -244,7 +244,7 @@ bool PathFollow3D::get_cubic_interpolation() const { void PathFollow3D::_validate_property(PropertyInfo &property) const { if (property.name == "offset") { - float max = 10000; + real_t max = 10000; if (path && path->get_curve().is_valid()) { max = path->get_curve()->get_baked_length(); } @@ -307,13 +307,13 @@ void PathFollow3D::_bind_methods() { BIND_ENUM_CONSTANT(ROTATION_ORIENTED); } -void PathFollow3D::set_offset(float p_offset) { +void PathFollow3D::set_offset(real_t p_offset) { delta_offset = p_offset - offset; offset = p_offset; if (path) { if (path->get_curve().is_valid()) { - float path_length = path->get_curve()->get_baked_length(); + real_t path_length = path->get_curve()->get_baked_length(); if (loop) { offset = Math::fposmod(offset, path_length); @@ -329,39 +329,39 @@ void PathFollow3D::set_offset(float p_offset) { } } -void PathFollow3D::set_h_offset(float p_h_offset) { +void PathFollow3D::set_h_offset(real_t p_h_offset) { h_offset = p_h_offset; if (path) { _update_transform(); } } -float PathFollow3D::get_h_offset() const { +real_t PathFollow3D::get_h_offset() const { return h_offset; } -void PathFollow3D::set_v_offset(float p_v_offset) { +void PathFollow3D::set_v_offset(real_t p_v_offset) { v_offset = p_v_offset; if (path) { _update_transform(); } } -float PathFollow3D::get_v_offset() const { +real_t PathFollow3D::get_v_offset() const { return v_offset; } -float PathFollow3D::get_offset() const { +real_t PathFollow3D::get_offset() const { return offset; } -void PathFollow3D::set_unit_offset(float p_unit_offset) { +void PathFollow3D::set_unit_offset(real_t p_unit_offset) { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { set_offset(p_unit_offset * path->get_curve()->get_baked_length()); } } -float PathFollow3D::get_unit_offset() const { +real_t PathFollow3D::get_unit_offset() const { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { return get_offset() / path->get_curve()->get_baked_length(); } else { diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 8545370a4a..1ffe291100 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -83,17 +83,17 @@ protected: static void _bind_methods(); public: - void set_offset(float p_offset); - float get_offset() const; + void set_offset(real_t p_offset); + real_t get_offset() const; - void set_h_offset(float p_h_offset); - float get_h_offset() const; + void set_h_offset(real_t p_h_offset); + real_t get_h_offset() const; - void set_v_offset(float p_v_offset); - float get_v_offset() const; + void set_v_offset(real_t p_v_offset); + real_t get_v_offset() const; - void set_unit_offset(float p_unit_offset); - float get_unit_offset() const; + void set_unit_offset(real_t p_unit_offset); + real_t get_unit_offset() 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 100e3563a3..53ec07f1ce 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -117,9 +117,9 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_i return Ref<KinematicCollision3D>(); } -bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) { +bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) { Transform3D gt = get_global_transform(); - bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes); + bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude); // Restore direction of motion to be along original motion, // in order to avoid sliding due to recovery, @@ -1090,6 +1090,9 @@ void CharacterBody3D::move_and_slide() { bool was_on_floor = on_floor; + // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky + float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); + for (int i = 0; i < 3; i++) { if (locked_axis & (1 << i)) { linear_velocity[i] = 0.0; @@ -1097,28 +1100,40 @@ void CharacterBody3D::move_and_slide() { } Vector3 current_floor_velocity = floor_velocity; - if (on_floor && on_floor_body.is_valid()) { + if ((on_floor || on_wall) && on_floor_body.is_valid()) { //this approach makes sure there is less delay between the actual body velocity and the one we saved PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(on_floor_body); if (bs) { - current_floor_velocity = bs->get_linear_velocity(); + Transform3D gt = get_global_transform(); + Vector3 local_position = gt.origin - bs->get_transform().origin; + current_floor_velocity = bs->get_velocity_at_local_position(local_position); } } - // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - Vector3 motion = (floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); - + motion_results.clear(); on_floor = false; - on_floor_body = RID(); on_ceiling = false; on_wall = false; - motion_results.clear(); floor_normal = Vector3(); floor_velocity = Vector3(); + if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) { + PhysicsServer3D::MotionResult floor_result; + Set<RID> exclude; + exclude.insert(on_floor_body); + if (move_and_collide(current_floor_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) { + motion_results.push_back(floor_result); + _set_collision_direction(floor_result); + } + } + + on_floor_body = RID(); + Vector3 motion = linear_velocity * delta; + // No sliding on first attempt to keep floor motion stable when possible, // when stop on slope is enabled. bool sliding_enabled = !stop_on_slope; + for (int iteration = 0; iteration < max_slides; ++iteration) { PhysicsServer3D::MotionResult result; bool found_collision = false; @@ -1142,35 +1157,19 @@ void CharacterBody3D::move_and_slide() { found_collision = true; motion_results.push_back(result); - - if (up_direction == Vector3()) { - //all is a wall - on_wall = true; - } else { - if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor - - on_floor = true; - floor_normal = result.collision_normal; - on_floor_body = result.collider; - floor_velocity = result.collider_velocity; - - if (stop_on_slope) { - if ((body_velocity_normal + up_direction).length() < 0.01) { - Transform3D gt = get_global_transform(); - if (result.motion.length() > margin) { - gt.origin -= result.motion.slide(up_direction); - } else { - gt.origin -= result.motion; - } - set_global_transform(gt); - linear_velocity = Vector3(); - return; - } + _set_collision_direction(result); + + if (on_floor && stop_on_slope) { + if ((body_velocity_normal + up_direction).length() < 0.01) { + Transform3D gt = get_global_transform(); + if (result.motion.length() > margin) { + gt.origin -= result.motion.slide(up_direction); + } else { + gt.origin -= result.motion; } - } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling - on_ceiling = true; - } else { - on_wall = true; + set_global_transform(gt); + linear_velocity = Vector3(); + return; } } @@ -1196,6 +1195,11 @@ void CharacterBody3D::move_and_slide() { } } + if (!on_floor && !on_wall) { + // Add last platform velocity when just left a moving platform. + linear_velocity += current_floor_velocity; + } + if (!was_on_floor || snap == Vector3()) { return; } @@ -1231,6 +1235,29 @@ void CharacterBody3D::move_and_slide() { } } +void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result) { + on_floor = false; + on_ceiling = false; + on_wall = false; + if (up_direction == Vector3()) { + //all is a wall + on_wall = true; + } else { + if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + on_floor = true; + floor_normal = p_result.collision_normal; + on_floor_body = p_result.collider; + floor_velocity = p_result.collider_velocity; + } else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + on_ceiling = true; + } else { + on_wall = true; + on_floor_body = p_result.collider; + floor_velocity = p_result.collider_velocity; + } + } +} + bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) { PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 0ef9c78f3b..227e6d43b6 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -53,7 +53,7 @@ protected: Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001); public: - bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true); + bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>()); bool test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001); void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); @@ -298,6 +298,8 @@ private: Ref<KinematicCollision3D> _get_slide_collision(int p_bounce); + void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result); + bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result); void set_safe_margin(real_t p_margin); diff --git a/scene/3d/proximity_group_3d.h b/scene/3d/proximity_group_3d.h index 05aa00b228..e45adc3040 100644 --- a/scene/3d/proximity_group_3d.h +++ b/scene/3d/proximity_group_3d.h @@ -49,7 +49,7 @@ private: DispatchMode dispatch_mode = MODE_PROXY; Vector3 grid_radius = Vector3(1, 1, 1); - float cell_size = 1.0; + real_t cell_size = 1.0; uint32_t group_version = 0; void _clear_groups(); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 9ce4c37457..86e2af7df5 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -366,7 +366,7 @@ void Skeleton3D::clear_bones_global_pose_override() { _make_dirty(); } -void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, float p_amount, bool p_persistent) { +void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) { ERR_FAIL_INDEX(p_bone, bones.size()); bones.write[p_bone].global_pose_override_amount = p_amount; bones.write[p_bone].global_pose_override = p_pose; diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 2f6e416c8c..3fdf5321a5 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -85,7 +85,7 @@ private: bool custom_pose_enable = false; Transform3D custom_pose; - float global_pose_override_amount = 0.0; + real_t global_pose_override_amount = 0.0; bool global_pose_override_reset = false; Transform3D global_pose_override; @@ -147,7 +147,7 @@ public: Transform3D get_bone_global_pose_no_override(int p_bone) const; void clear_bones_global_pose_override(); - void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, float p_amount, bool p_persistent = false); + void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false); void set_bone_enabled(int p_bone, bool p_enabled); bool is_bone_enabled(int p_bone) const; diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 1005d51e63..a891566633 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -85,7 +85,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain chain_sub_tip = p_task->skeleton->get_bone_parent(chain_sub_tip); } - BoneId middle_chain_item_id = (((float)sub_chain_size) * 0.5); + BoneId middle_chain_item_id = (BoneId)(sub_chain_size * 0.5); // Build chain by reading chain ids in reverse order // For each chain item id will be created a ChainItem if doesn't exists diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index a901920dbe..a28382f4cb 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -132,12 +132,12 @@ Color SpriteBase3D::get_modulate() const { return modulate; } -void SpriteBase3D::set_pixel_size(float p_amount) { +void SpriteBase3D::set_pixel_size(real_t p_amount) { pixel_size = p_amount; _queue_update(); } -float SpriteBase3D::get_pixel_size() const { +real_t SpriteBase3D::get_pixel_size() const { return pixel_size; } @@ -203,7 +203,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const { return Ref<TriangleMesh>(); } - float pixel_size = get_pixel_size(); + real_t pixel_size = get_pixel_size(); Vector2 vertices[4] = { @@ -470,7 +470,7 @@ void Sprite3D::_draw() { Color color = _get_color_accum(); color.a *= get_opacity(); - float pixel_size = get_pixel_size(); + real_t pixel_size = get_pixel_size(); Vector2 vertices[4] = { @@ -837,7 +837,7 @@ void AnimatedSprite3D::_draw() { Color color = _get_color_accum(); color.a *= get_opacity(); - float pixel_size = get_pixel_size(); + real_t pixel_size = get_pixel_size(); Vector2 vertices[4] = { @@ -1037,7 +1037,7 @@ void AnimatedSprite3D::_notification(int p_what) { return; //do nothing } - float remaining = get_process_delta_time(); + double remaining = get_process_delta_time(); while (remaining) { if (timeout <= 0) { @@ -1059,7 +1059,7 @@ void AnimatedSprite3D::_notification(int p_what) { emit_signal(SceneStringNames::get_singleton()->frame_changed); } - float to_process = MIN(timeout, remaining); + double to_process = MIN(timeout, remaining); remaining -= to_process; timeout -= to_process; } diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 404ef57e6a..d35b9ffe1b 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -72,7 +72,7 @@ private: float opacity = 1.0; Vector3::Axis axis = Vector3::AXIS_Z; - float pixel_size = 0.01; + real_t pixel_size = 0.01; AABB aabb; RID mesh; @@ -130,8 +130,8 @@ public: void set_opacity(float p_amount); float get_opacity() const; - void set_pixel_size(float p_amount); - float get_pixel_size() const; + void set_pixel_size(real_t p_amount); + real_t get_pixel_size() const; void set_axis(Vector3::Axis p_axis); Vector3::Axis get_axis() const; @@ -213,7 +213,7 @@ class AnimatedSprite3D : public SpriteBase3D { bool centered = false; - float timeout = 0; + double timeout = 0.0; void _res_changed(); diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp index 5b5cc06456..a027749eaa 100644 --- a/scene/3d/velocity_tracker_3d.cpp +++ b/scene/3d/velocity_tracker_3d.cpp @@ -61,16 +61,16 @@ void VelocityTracker3D::update_position(const Vector3 &p_position) { Vector3 VelocityTracker3D::get_tracked_linear_velocity() const { Vector3 linear_velocity; - float max_time = 1 / 5.0; //maximum time to interpolate a velocity + double max_time = 1 / 5.0; //maximum time to interpolate a velocity Vector3 distance_accum; - float time_accum = 0.0; - float base_time = 0.0; + double time_accum = 0.0; + double base_time = 0.0; if (position_history_len) { if (physics_step) { uint64_t base = Engine::get_singleton()->get_physics_frames(); - base_time = float(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second(); + base_time = double(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second(); } else { uint64_t base = Engine::get_singleton()->get_frame_ticks(); base_time = double(base - position_history[0].frame) / 1000000.0; @@ -78,12 +78,12 @@ Vector3 VelocityTracker3D::get_tracked_linear_velocity() const { } for (int i = 0; i < position_history_len - 1; i++) { - float delta = 0.0; + double delta = 0.0; uint64_t diff = position_history[i].frame - position_history[i + 1].frame; Vector3 distance = position_history[i].position - position_history[i + 1].position; if (physics_step) { - delta = float(diff) / Engine::get_singleton()->get_iterations_per_second(); + delta = double(diff) / Engine::get_singleton()->get_iterations_per_second(); } else { delta = double(diff) / 1000000.0; } diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index f1b9708f91..6124326d2d 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -56,20 +56,20 @@ static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 Vector3 v1 = p_vtx[2] - p_vtx[0]; Vector3 v2 = p_pos - p_vtx[0]; - float d00 = v0.dot(v0); - float d01 = v0.dot(v1); - float d11 = v1.dot(v1); - float d20 = v2.dot(v0); - float d21 = v2.dot(v1); - float denom = (d00 * d11 - d01 * d01); + real_t d00 = v0.dot(v0); + real_t d01 = v0.dot(v1); + real_t d11 = v1.dot(v1); + real_t d20 = v2.dot(v0); + real_t d21 = v2.dot(v1); + real_t denom = (d00 * d11 - d01 * d01); if (denom == 0) { r_uv = p_uv[0]; r_normal = p_normal[0]; return; } - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0f - v - w; + real_t v = (d11 * d20 - d01 * d21) / denom; + real_t w = (d00 * d21 - d01 * d20) / denom; + real_t u = 1.0f - v - w; r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized(); @@ -81,7 +81,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co //find best axis to map to, for scanning values int closest_axis = 0; - float closest_dot = 0; + real_t closest_dot = 0; Plane plane = Plane(p_vtx[0], p_vtx[1], p_vtx[2]); Vector3 normal = plane.normal; @@ -89,7 +89,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co for (int i = 0; i < 3; i++) { Vector3 axis; axis[i] = 1.0; - float dot = ABS(normal.dot(axis)); + real_t dot = ABS(normal.dot(axis)); if (i == 0 || dot > closest_dot) { closest_axis = i; closest_dot = dot; @@ -103,8 +103,8 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co Vector3 t2; t2[(closest_axis + 2) % 3] = 1.0; - t1 *= p_aabb.size[(closest_axis + 1) % 3] / float(color_scan_cell_width); - t2 *= p_aabb.size[(closest_axis + 2) % 3] / float(color_scan_cell_width); + t1 *= p_aabb.size[(closest_axis + 1) % 3] / real_t(color_scan_cell_width); + t2 *= p_aabb.size[(closest_axis + 2) % 3] / real_t(color_scan_cell_width); Color albedo_accum; Color emission_accum; @@ -114,10 +114,10 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co //map to a grid average in the best axis for this face for (int i = 0; i < color_scan_cell_width; i++) { - Vector3 ofs_i = float(i) * t1; + Vector3 ofs_i = real_t(i) * t1; for (int j = 0; j < color_scan_cell_width; j++) { - Vector3 ofs_j = float(j) * t2; + Vector3 ofs_j = real_t(j) * t2; Vector3 from = p_aabb.position + ofs_i + ofs_j; Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis]; @@ -155,8 +155,8 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co lnormal = normal; } - int uv_x = CLAMP(int(Math::fposmod(uv.x, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); - int uv_y = CLAMP(int(Math::fposmod(uv.y, 1.0f) * bake_texture_size), 0, bake_texture_size - 1); + int uv_x = CLAMP(int(Math::fposmod(uv.x, (real_t)1.0) * bake_texture_size), 0, bake_texture_size - 1); + int uv_y = CLAMP(int(Math::fposmod(uv.y, (real_t)1.0) * bake_texture_size), 0, bake_texture_size - 1); int ofs = uv_y * bake_texture_size + uv_x; albedo_accum.r += p_material.albedo[ofs].r; @@ -187,8 +187,8 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co lnormal = normal; } - int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); - int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); + int uv_x = CLAMP(Math::fposmod(uv.x, (real_t)1.0) * bake_texture_size, 0, bake_texture_size - 1); + int uv_y = CLAMP(Math::fposmod(uv.y, (real_t)1.0) * bake_texture_size, 0, bake_texture_size - 1); int ofs = uv_y * bake_texture_size + uv_x; @@ -636,7 +636,7 @@ void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) { } axis_cell_size[i] = axis_cell_size[longest_axis]; - float axis_size = po2_bounds.size[longest_axis]; + real_t axis_size = po2_bounds.size[longest_axis]; //shrink until fit subdiv while (axis_size / 2.0 >= po2_bounds.size[i]) { @@ -954,7 +954,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() { Vector3 face_points[4]; for (int j = 0; j < 4; j++) { - float v[3]; + real_t v[3]; v[0] = 1.0; v[1] = 1 - 2 * ((j >> 1) & 1); v[2] = v[1] * (1 - 2 * (j & 1)); diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index b04c7e2858..e620f33478 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -124,7 +124,7 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const { return res; }; -Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) const { +Vector3 XRCamera3D::project_position(const Point2 &p_point, real_t p_z_depth) const { // get our XRServer XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, Vector3()); @@ -544,7 +544,7 @@ void XROrigin3D::clear_tracked_camera_if(XRCamera3D *p_tracked_camera) { }; }; -float XROrigin3D::get_world_scale() const { +real_t XROrigin3D::get_world_scale() const { // get our XRServer XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 1.0); @@ -552,7 +552,7 @@ float XROrigin3D::get_world_scale() const { return xr_server->get_world_scale(); }; -void XROrigin3D::set_world_scale(float p_world_scale) { +void XROrigin3D::set_world_scale(real_t p_world_scale) { // get our XRServer XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 90079f5fe9..312287a93b 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -54,7 +54,7 @@ public: virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const override; virtual Point2 unproject_position(const Vector3 &p_pos) const override; - virtual Vector3 project_position(const Point2 &p_point, float p_z_depth) const override; + virtual Vector3 project_position(const Point2 &p_point, real_t p_z_depth) const override; virtual Vector<Plane> get_frustum() const override; XRCamera3D() {} @@ -163,8 +163,8 @@ public: void set_tracked_camera(XRCamera3D *p_tracked_camera); void clear_tracked_camera_if(XRCamera3D *p_tracked_camera); - float get_world_scale() const; - void set_world_scale(float p_world_scale); + real_t get_world_scale() const; + void set_world_scale(real_t p_world_scale); XROrigin3D() {} ~XROrigin3D() {} diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index 6e5d964b76..0167992baf 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -219,7 +219,7 @@ void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<Animatio } } -float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { +double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek) { if (blend_points_used == 0) { return 0.0; } @@ -229,7 +229,7 @@ float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false); } - float blend_pos = get_parameter(blend_position); + double blend_pos = get_parameter(blend_position); float weights[MAX_BLEND_POINTS] = {}; diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index 8886e6c679..6730c09fd4 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -93,7 +93,7 @@ public: void set_value_label(const String &p_label); String get_value_label() const; - float process(float p_time, bool p_seek) override; + double process(double p_time, bool p_seek) override; String get_caption() const override; Ref<AnimationNode> get_child_by_name(const StringName &p_name) override; diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index d88a9badf4..145e7c605b 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -431,12 +431,12 @@ void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vect r_weights[2] = w; } -float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { +double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek) { _update_triangles(); Vector2 blend_pos = get_parameter(blend_position); int closest = get_parameter(this->closest); - float length_internal = get_parameter(this->length_internal); + double length_internal = get_parameter(this->length_internal); float mind = 0.0; //time of min distance point if (blend_mode == BLEND_MODE_INTERPOLATED) { diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 65d09a550d..a919fff1d2 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -126,7 +126,7 @@ public: void set_y_label(const String &p_label); String get_y_label() const; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; virtual String get_caption() const override; Vector2 get_closest_point(const Vector2 &p_point); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 4bddae3b14..049f3483ff 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -63,11 +63,11 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { } } -float AnimationNodeAnimation::process(float p_time, bool p_seek) { +double AnimationNodeAnimation::process(double p_time, bool p_seek) { AnimationPlayer *ap = state->player; ERR_FAIL_COND_V(!ap, 0); - float time = get_parameter(this->time); + double time = get_parameter(this->time); if (!ap->has_animation(animation)) { AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(parent); @@ -84,7 +84,7 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { Ref<Animation> anim = ap->get_animation(animation); - float step; + double step; if (p_seek) { time = p_time; @@ -94,7 +94,7 @@ float AnimationNodeAnimation::process(float p_time, bool p_seek) { step = p_time; } - float anim_size = anim->get_length(); + double anim_size = anim->get_length(); if (anim->has_loop()) { if (anim_size) { @@ -202,12 +202,12 @@ bool AnimationNodeOneShot::has_filter() const { return true; } -float AnimationNodeOneShot::process(float p_time, bool p_seek) { +double AnimationNodeOneShot::process(double p_time, bool p_seek) { bool active = get_parameter(this->active); bool prev_active = get_parameter(this->prev_active); - float time = get_parameter(this->time); - float remaining = get_parameter(this->remaining); - float time_to_restart = get_parameter(this->time_to_restart); + double time = get_parameter(this->time); + double remaining = get_parameter(this->remaining); + double time_to_restart = get_parameter(this->time_to_restart); if (!active) { //make it as if this node doesn't exist, pass input 0 by. @@ -370,9 +370,9 @@ bool AnimationNodeAdd2::has_filter() const { return true; } -float AnimationNodeAdd2::process(float p_time, bool p_seek) { - float amount = get_parameter(add_amount); - float rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); +double AnimationNodeAdd2::process(double p_time, bool p_seek) { + double amount = get_parameter(add_amount); + double rem0 = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync); return rem0; @@ -416,10 +416,10 @@ bool AnimationNodeAdd3::has_filter() const { return true; } -float AnimationNodeAdd3::process(float p_time, bool p_seek) { - float amount = get_parameter(add_amount); +double AnimationNodeAdd3::process(double p_time, bool p_seek) { + double amount = get_parameter(add_amount); blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_PASS, !sync); - float rem0 = blend_input(1, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); + double rem0 = blend_input(1, p_time, p_seek, 1.0, FILTER_IGNORE, !sync); blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_PASS, !sync); return rem0; @@ -452,11 +452,11 @@ String AnimationNodeBlend2::get_caption() const { return "Blend2"; } -float AnimationNodeBlend2::process(float p_time, bool p_seek) { - float amount = get_parameter(blend_amount); +double AnimationNodeBlend2::process(double p_time, bool p_seek) { + double amount = get_parameter(blend_amount); - float rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync); - float rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync); + double rem0 = blend_input(0, p_time, p_seek, 1.0 - amount, FILTER_BLEND, !sync); + double rem1 = blend_input(1, p_time, p_seek, amount, FILTER_PASS, !sync); return amount > 0.5 ? rem1 : rem0; //hacky but good enough } @@ -507,11 +507,11 @@ bool AnimationNodeBlend3::is_using_sync() const { return sync; } -float AnimationNodeBlend3::process(float p_time, bool p_seek) { - float amount = get_parameter(blend_amount); - float rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync); - float rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync); - float rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync); +double AnimationNodeBlend3::process(double p_time, bool p_seek) { + double amount = get_parameter(blend_amount); + double rem0 = blend_input(0, p_time, p_seek, MAX(0, -amount), FILTER_IGNORE, !sync); + double rem1 = blend_input(1, p_time, p_seek, 1.0 - ABS(amount), FILTER_IGNORE, !sync); + double rem2 = blend_input(2, p_time, p_seek, MAX(0, amount), FILTER_IGNORE, !sync); return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); //hacky but good enough } @@ -545,8 +545,8 @@ String AnimationNodeTimeScale::get_caption() const { return "TimeScale"; } -float AnimationNodeTimeScale::process(float p_time, bool p_seek) { - float scale = get_parameter(this->scale); +double AnimationNodeTimeScale::process(double p_time, bool p_seek) { + double scale = get_parameter(this->scale); if (p_seek) { return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false); } else { @@ -575,12 +575,12 @@ String AnimationNodeTimeSeek::get_caption() const { return "Seek"; } -float AnimationNodeTimeSeek::process(float p_time, bool p_seek) { - float seek_pos = get_parameter(this->seek_pos); +double AnimationNodeTimeSeek::process(double p_time, bool p_seek) { + double seek_pos = get_parameter(this->seek_pos); if (p_seek) { return blend_input(0, p_time, true, 1.0, FILTER_IGNORE, false); } else if (seek_pos >= 0) { - float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false); + double ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false); set_parameter(this->seek_pos, -1.0); //reset return ret; } else { @@ -676,13 +676,13 @@ float AnimationNodeTransition::get_cross_fade_time() const { return xfade; } -float AnimationNodeTransition::process(float p_time, bool p_seek) { +double AnimationNodeTransition::process(double p_time, bool p_seek) { int current = get_parameter(this->current); int prev = get_parameter(this->prev); int prev_current = get_parameter(this->prev_current); - float time = get_parameter(this->time); - float prev_xfading = get_parameter(this->prev_xfading); + double time = get_parameter(this->time); + double prev_xfading = get_parameter(this->prev_xfading); bool switched = current != prev_current; @@ -794,7 +794,7 @@ String AnimationNodeOutput::get_caption() const { return "Output"; } -float AnimationNodeOutput::process(float p_time, bool p_seek) { +double AnimationNodeOutput::process(double p_time, bool p_seek) { return blend_input(0, p_time, p_seek, 1.0); } @@ -1007,7 +1007,7 @@ String AnimationNodeBlendTree::get_caption() const { return "BlendTree"; } -float AnimationNodeBlendTree::process(float p_time, bool p_seek) { +double AnimationNodeBlendTree::process(double p_time, bool p_seek) { Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node; return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, 1.0); } diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index d82658c8c2..8508aaf71b 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -53,7 +53,7 @@ public: static Vector<String> (*get_editable_animation_list)(); virtual String get_caption() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; void set_animation(const StringName &p_name); StringName get_animation() const; @@ -122,7 +122,7 @@ public: bool is_using_sync() const; virtual bool has_filter() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; AnimationNodeOneShot(); }; @@ -148,7 +148,7 @@ public: bool is_using_sync() const; virtual bool has_filter() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; AnimationNodeAdd2(); }; @@ -172,7 +172,7 @@ public: bool is_using_sync() const; virtual bool has_filter() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; AnimationNodeAdd3(); }; @@ -191,7 +191,7 @@ public: virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; virtual String get_caption() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; void set_use_sync(bool p_sync); bool is_using_sync() const; @@ -218,7 +218,7 @@ public: void set_use_sync(bool p_sync); bool is_using_sync() const; - float process(float p_time, bool p_seek) override; + double process(double p_time, bool p_seek) override; AnimationNodeBlend3(); }; @@ -236,7 +236,7 @@ public: virtual String get_caption() const override; - float process(float p_time, bool p_seek) override; + double process(double p_time, bool p_seek) override; AnimationNodeTimeScale(); }; @@ -255,7 +255,7 @@ public: virtual String get_caption() const override; - float process(float p_time, bool p_seek) override; + double process(double p_time, bool p_seek) override; AnimationNodeTimeSeek(); }; @@ -313,7 +313,7 @@ public: void set_cross_fade_time(float p_fade); float get_cross_fade_time() const; - float process(float p_time, bool p_seek) override; + double process(double p_time, bool p_seek) override; AnimationNodeTransition(); }; @@ -323,7 +323,7 @@ class AnimationNodeOutput : public AnimationNode { public: virtual String get_caption() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; AnimationNodeOutput(); }; @@ -390,7 +390,7 @@ public: void get_node_connections(List<NodeConnection> *r_connections) const; virtual String get_caption() const override; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; void get_node_list(List<StringName> *r_list); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index bf53b554bf..9fc1dbd0c6 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -286,7 +286,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta return true; } -float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, float p_time, bool p_seek) { +double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek) { //if not playing and it can restart, then restart if (!playing && start_request == StringName()) { if (!stop_request && p_state_machine->start_node) { @@ -790,7 +790,7 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const { return graph_offset; } -float AnimationNodeStateMachine::process(float p_time, bool p_seek) { +double AnimationNodeStateMachine::process(double p_time, bool p_seek) { Ref<AnimationNodeStateMachinePlayback> playback = get_parameter(this->playback); ERR_FAIL_COND_V(playback.is_null(), 0.0); diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index 9c1bca63c3..6f0e3107fd 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -114,7 +114,7 @@ class AnimationNodeStateMachinePlayback : public Resource { bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel); - float process(AnimationNodeStateMachine *p_state_machine, float p_time, bool p_seek); + double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek); protected: static void _bind_methods(); @@ -210,7 +210,7 @@ public: void set_graph_offset(const Vector2 &p_offset); Vector2 get_graph_offset() const; - virtual float process(float p_time, bool p_seek) override; + virtual double process(double p_time, bool p_seek) override; virtual String get_caption() const override; virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 67b6205a65..5d200ebf86 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -341,7 +341,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov } } -void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started) { +void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double p_time, double p_delta, float p_interp, bool p_is_current, bool p_seeked, bool p_started) { _ensure_node_caches(p_anim); ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count()); @@ -723,7 +723,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float continue; } - float pos = a->track_get_key_time(i, idx); + double pos = a->track_get_key_time(i, idx); StringName anim_name = a->animation_track_get_key_animation(i, idx); if (String(anim_name) == "[stop]" || !player->has_animation(anim_name)) { @@ -732,12 +732,12 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float Ref<Animation> anim = player->get_animation(anim_name); - float at_anim_pos; + double at_anim_pos; if (anim->has_loop()) { - at_anim_pos = Math::fposmod(p_time - pos, anim->get_length()); //seek to loop + at_anim_pos = Math::fposmod(p_time - pos, (double)anim->get_length()); //seek to loop } else { - at_anim_pos = MAX(anim->get_length(), p_time - pos); //seek to end + at_anim_pos = MAX((double)anim->get_length(), p_time - pos); //seek to end } if (player->is_playing() || p_seeked) { @@ -776,11 +776,11 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float } } -void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started) { - float delta = p_delta * speed_scale * cd.speed_scale; - float next_pos = cd.pos + delta; +void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started) { + double delta = p_delta * speed_scale * cd.speed_scale; + double next_pos = cd.pos + delta; - float len = cd.from->animation->get_length(); + real_t len = cd.from->animation->get_length(); bool loop = cd.from->animation->has_loop(); if (!loop) { @@ -808,7 +808,7 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f } } else { - float looped_next_pos = Math::fposmod(next_pos, len); + double looped_next_pos = Math::fposmod(next_pos, (double)len); if (looped_next_pos == 0 && next_pos != 0) { // Loop multiples of the length to it, rather than 0 // so state at time=length is previewable in the editor @@ -823,7 +823,7 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f _animation_process_animation(cd.from, cd.pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started); } -void AnimationPlayer::_animation_process2(float p_delta, bool p_started) { +void AnimationPlayer::_animation_process2(double p_delta, bool p_started) { Playback &c = playback; accum_pass++; @@ -927,7 +927,7 @@ void AnimationPlayer::_animation_update_transforms() { cache_update_bezier_size = 0; } -void AnimationPlayer::_animation_process(float p_delta) { +void AnimationPlayer::_animation_process(double p_delta) { if (playback.current.from) { end_reached = false; end_notify = false; @@ -1283,7 +1283,7 @@ float AnimationPlayer::get_playing_speed() const { return speed_scale * playback.current.speed_scale; } -void AnimationPlayer::seek(float p_time, bool p_update) { +void AnimationPlayer::seek(double p_time, bool p_update) { if (!playback.current.from) { if (playback.assigned) { ERR_FAIL_COND(!animation_set.has(playback.assigned)); @@ -1299,7 +1299,7 @@ void AnimationPlayer::seek(float p_time, bool p_update) { } } -void AnimationPlayer::seek_delta(float p_time, float p_delta) { +void AnimationPlayer::seek_delta(double p_time, float p_delta) { if (!playback.current.from) { if (playback.assigned) { ERR_FAIL_COND(!animation_set.has(playback.assigned)); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 7cd9de1fa1..b693e29bdf 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -215,13 +215,13 @@ private: NodePath root; - void _animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false); + void _animation_process_animation(AnimationData *p_anim, double p_time, double p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false); void _ensure_node_caches(AnimationData *p_anim, Node *p_root_override = nullptr); - void _animation_process_data(PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started); - void _animation_process2(float p_delta, bool p_started); + void _animation_process_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started); + void _animation_process2(double p_delta, bool p_started); void _animation_update_transforms(); - void _animation_process(float p_delta); + void _animation_process(double p_delta); void _node_removed(Node *p_node); void _stop_playing_caches(); @@ -306,8 +306,8 @@ public: void set_method_call_mode(AnimationMethodCallMode p_mode); AnimationMethodCallMode get_method_call_mode() const; - void seek(float p_time, bool p_update = false); - void seek_delta(float p_time, float p_delta); + void seek(double p_time, bool p_update = false); + void seek_delta(double p_time, float p_delta); float get_current_animation_position() const; float get_current_animation_length() const; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index e623309888..543545b90f 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -85,7 +85,7 @@ void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { } } -void AnimationNode::blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend) { +void AnimationNode::blend_animation(const StringName &p_animation, real_t p_time, real_t p_delta, bool p_seeked, real_t p_blend) { ERR_FAIL_COND(!state); ERR_FAIL_COND(!state->player->has_animation(p_animation)); @@ -115,13 +115,13 @@ void AnimationNode::blend_animation(const StringName &p_animation, float p_time, state->animation_states.push_back(anim_state); } -float AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections) { +real_t AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, real_t p_time, bool p_seek, const Vector<StringName> &p_connections) { base_path = p_base_path; parent = p_parent; connections = p_connections; state = p_state; - float t = process(p_time, p_seek); + real_t t = process(p_time, p_seek); state = nullptr; parent = nullptr; @@ -140,7 +140,7 @@ void AnimationNode::make_invalid(const String &p_reason) { state->invalid_reasons += String::utf8("• ") + p_reason; } -float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { +real_t AnimationNode::blend_input(int p_input, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize) { ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); ERR_FAIL_COND_V(!state, 0); @@ -158,8 +158,8 @@ float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p Ref<AnimationNode> node = blend_tree->get_node(node_name); //inputs.write[p_input].last_pass = state->last_pass; - float activity = 0.0; - float ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity); + real_t activity = 0.0; + real_t ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity); Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path); @@ -170,11 +170,11 @@ float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p return ret; } -float AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { +real_t AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize) { return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_blend, p_filter, p_optimize); } -float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize, float *r_max) { +real_t AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter, bool p_optimize, real_t *r_max) { ERR_FAIL_COND_V(!p_node.is_valid(), 0); ERR_FAIL_COND_V(!state, 0); @@ -184,8 +184,8 @@ float AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Strin p_node->blends.resize(blend_count); } - float *blendw = p_node->blends.ptrw(); - const float *blendr = blends.ptr(); + real_t *blendw = p_node->blends.ptrw(); + const real_t *blendr = blends.ptr(); bool any_valid = false; @@ -328,7 +328,7 @@ void AnimationNode::remove_input(int p_index) { emit_changed(); } -float AnimationNode::process(float p_time, bool p_seek) { +double AnimationNode::process(double p_time, bool p_seek) { if (get_script_instance()) { return get_script_instance()->call("_process", p_time, p_seek); } @@ -718,7 +718,7 @@ void AnimationTree::_clear_caches() { cache_valid = false; } -void AnimationTree::_process_graph(float p_delta) { +void AnimationTree::_process_graph(real_t p_delta) { _update_properties(); //if properties need updating, update them //check all tracks, see if they need modification @@ -790,7 +790,7 @@ void AnimationTree::_process_graph(float p_delta) { // root source blends root->blends.resize(state.track_count); - float *src_blendsw = root->blends.ptrw(); + real_t *src_blendsw = root->blends.ptrw(); for (int i = 0; i < state.track_count; i++) { src_blendsw[i] = 1.0; //by default all go to 1 for the root input } @@ -818,9 +818,9 @@ void AnimationTree::_process_graph(float p_delta) { for (const AnimationNode::AnimationState &as : state.animation_states) { Ref<Animation> a = as.animation; - float time = as.time; - float delta = as.delta; - float weight = as.blend; + double time = as.time; + double delta = as.delta; + real_t weight = as.blend; bool seeked = as.seeked; for (int i = 0; i < a->get_track_count(); i++) { @@ -840,7 +840,7 @@ void AnimationTree::_process_graph(float p_delta) { ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count); - float blend = (*as.track_blends)[blend_idx] * weight; + real_t blend = (*as.track_blends)[blend_idx] * weight; if (blend < CMP_EPSILON) { continue; //nothing to blend @@ -860,7 +860,7 @@ void AnimationTree::_process_graph(float p_delta) { t->scale = Vector3(1, 1, 1); } - float prev_time = time - delta; + real_t prev_time = time - delta; if (prev_time < 0) { if (!a->has_loop()) { prev_time = 0; @@ -928,7 +928,7 @@ void AnimationTree::_process_graph(float p_delta) { t->rot = rot; t->rot_blend_accum = blend; } else { - float rot_total = t->rot_blend_accum + blend; + real_t rot_total = t->rot_blend_accum + blend; t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized(); t->rot_blend_accum = rot_total; } @@ -1003,7 +1003,7 @@ void AnimationTree::_process_graph(float p_delta) { case Animation::TYPE_BEZIER: { TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); - float bezier = a->bezier_track_interpolate(i, time); + real_t bezier = a->bezier_track_interpolate(i, time); if (t->process_pass != process_pass) { t->value = bezier; @@ -1029,10 +1029,10 @@ void AnimationTree::_process_graph(float p_delta) { t->playing = false; playing_caches.erase(t); } else { - float start_ofs = a->audio_track_get_key_start_offset(i, idx); + real_t start_ofs = a->audio_track_get_key_start_offset(i, idx); start_ofs += time - a->track_get_key_time(i, idx); - float end_ofs = a->audio_track_get_key_end_offset(i, idx); - float len = stream->get_length(); + real_t end_ofs = a->audio_track_get_key_end_offset(i, idx); + real_t len = stream->get_length(); if (start_ofs > len - end_ofs) { t->object->call("stop"); @@ -1068,9 +1068,9 @@ void AnimationTree::_process_graph(float p_delta) { t->playing = false; playing_caches.erase(t); } else { - float start_ofs = a->audio_track_get_key_start_offset(i, idx); - float end_ofs = a->audio_track_get_key_end_offset(i, idx); - float len = stream->get_length(); + real_t start_ofs = a->audio_track_get_key_start_offset(i, idx); + real_t end_ofs = a->audio_track_get_key_end_offset(i, idx); + real_t len = stream->get_length(); t->object->call("set_stream", stream); t->object->call("play", start_ofs); @@ -1093,7 +1093,7 @@ void AnimationTree::_process_graph(float p_delta) { if (!loop && time < t->start) { stop = true; } else if (t->len > 0) { - float len = t->start > time ? (a->get_length() - t->start) + time : time - t->start; + real_t len = t->start > time ? (a->get_length() - t->start) + time : time - t->start; if (len > t->len) { stop = true; @@ -1109,7 +1109,7 @@ void AnimationTree::_process_graph(float p_delta) { } } - float db = Math::linear2db(MAX(blend, 0.00001)); + real_t db = Math::linear2db(MAX(blend, 0.00001)); if (t->object->has_method("set_unit_db")) { t->object->call("set_unit_db", db); } else { @@ -1132,7 +1132,7 @@ void AnimationTree::_process_graph(float p_delta) { continue; } - float pos = a->track_get_key_time(i, idx); + double pos = a->track_get_key_time(i, idx); StringName anim_name = a->animation_track_get_key_animation(i, idx); if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) { @@ -1141,10 +1141,10 @@ void AnimationTree::_process_graph(float p_delta) { Ref<Animation> anim = player2->get_animation(anim_name); - float at_anim_pos; + real_t at_anim_pos; if (anim->has_loop()) { - at_anim_pos = Math::fposmod(time - pos, anim->get_length()); //seek to loop + at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); //seek to loop } else { at_anim_pos = MAX(anim->get_length(), time - pos); //seek to end } @@ -1238,7 +1238,7 @@ void AnimationTree::_process_graph(float p_delta) { } } -void AnimationTree::advance(float p_time) { +void AnimationTree::advance(real_t p_time) { _process_graph(p_time); } @@ -1443,7 +1443,7 @@ void AnimationTree::rename_parameter(const String &p_base, const String &p_new_b _update_properties(); } -float AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const { +real_t AnimationTree::get_connection_activity(const StringName &p_path, int p_connection) const { if (!input_activity_map_get.has(p_path)) { return 0; } diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 60e0c7200a..59bbc5b4da 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -57,16 +57,16 @@ public: Vector<Input> inputs; - float process_input(int p_input, float p_time, bool p_seek, float p_blend); + real_t process_input(int p_input, real_t p_time, bool p_seek, real_t p_blend); friend class AnimationTree; struct AnimationState { Ref<Animation> animation; - float time = 0.0; - float delta = 0.0; - const Vector<float> *track_blends = nullptr; - float blend = 0.0; + double time = 0.0; + double delta = 0.0; + const Vector<real_t> *track_blends = nullptr; + real_t blend = 0.0; bool seeked = false; }; @@ -81,10 +81,10 @@ public: uint64_t last_pass = 0; }; - Vector<float> blends; + Vector<real_t> blends; State *state = nullptr; - float _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections); + real_t _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, real_t p_time, bool p_seek, const Vector<StringName> &p_connections); void _pre_update_animations(HashMap<NodePath, int> *track_map); //all this is temporary @@ -98,12 +98,12 @@ public: Array _get_filters() const; void _set_filters(const Array &p_filters); friend class AnimationNodeBlendTree; - float _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = nullptr); + real_t _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, real_t *r_max = nullptr); protected: - void blend_animation(const StringName &p_animation, float p_time, float p_delta, bool p_seeked, float p_blend); - float blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); - float blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); + void blend_animation(const StringName &p_animation, real_t p_time, real_t p_delta, bool p_seeked, real_t p_blend); + real_t blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); + real_t blend_input(int p_input, real_t p_time, bool p_seek, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true); void make_invalid(const String &p_reason); static void _bind_methods(); @@ -126,7 +126,7 @@ public: virtual void get_child_nodes(List<ChildNode> *r_child_nodes); - virtual float process(float p_time, bool p_seek); + virtual double process(double p_time, bool p_seek); virtual String get_caption() const; int get_input_count() const; @@ -191,7 +191,7 @@ private: int bone_idx = -1; Vector3 loc; Quaternion rot; - float rot_blend_accum = 0.0; + real_t rot_blend_accum = 0.0; Vector3 scale; TrackCacheTransform() { @@ -210,7 +210,7 @@ private: }; struct TrackCacheBezier : public TrackCache { - float value = 0.0; + real_t value = 0.0; Vector<StringName> subpath; TrackCacheBezier() { type = Animation::TYPE_BEZIER; @@ -219,8 +219,8 @@ private: struct TrackCacheAudio : public TrackCache { bool playing = false; - float start = 0.0; - float len = 0.0; + real_t start = 0.0; + real_t len = 0.0; TrackCacheAudio() { type = Animation::TYPE_AUDIO; @@ -251,7 +251,7 @@ private: void _clear_caches(); bool _update_caches(AnimationPlayer *player); - void _process_graph(float p_delta); + void _process_graph(real_t p_delta); uint64_t setup_pass = 1; uint64_t process_pass = 1; @@ -271,7 +271,7 @@ private: struct Activity { uint64_t last_pass = 0; - float activity = 0.0; + real_t activity = 0.0; }; HashMap<StringName, Vector<Activity>> input_activity_map; @@ -312,8 +312,8 @@ public: Transform3D get_root_motion_transform() const; - float get_connection_activity(const StringName &p_path, int p_connection) const; - void advance(float p_time); + real_t get_connection_activity(const StringName &p_path, int p_connection) const; + void advance(real_t p_time); void rename_parameter(const String &p_base, const String &p_new_base); diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h index 55fd2d2b73..d64c8bc675 100644 --- a/scene/animation/root_motion_view.h +++ b/scene/animation/root_motion_view.h @@ -39,8 +39,8 @@ class RootMotionView : public VisualInstance3D { public: Ref<ImmediateMesh> immediate; NodePath path; - float cell_size = 1.0; - float radius = 10.0; + real_t cell_size = 1.0; + real_t radius = 10.0; bool use_in_game = false; Color color = Color(0.5, 0.5, 1.0); bool first = true; diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 83ecf1d534..635f3c51b9 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -49,9 +49,6 @@ GradientEdit::GradientEdit() { popup->add_child(picker); add_child(popup); - - checker = Ref<ImageTexture>(memnew(ImageTexture)); - Ref<Image> img = memnew(Image(checker_bg_png)); } int GradientEdit::_get_point_from_pos(int x) { @@ -311,7 +308,7 @@ void GradientEdit::_notification(int p_what) { int total_w = get_size().width - get_size().height - SPACING; //Draw checker pattern for ramp - _draw_checker(0, 0, total_w, h); + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true); //Draw color ramp Gradient::Point prev; @@ -378,7 +375,7 @@ void GradientEdit::_notification(int p_what) { } //Draw "button" for color selector - _draw_checker(total_w + SPACING, 0, h, h); + draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + SPACING, 0, h, h), true); if (grabbed != -1) { //Draw with selection color draw_rect(Rect2(total_w + SPACING, 0, h, h), points[grabbed].color); @@ -405,27 +402,6 @@ void GradientEdit::_notification(int p_what) { } } -void GradientEdit::_draw_checker(int x, int y, int w, int h) { - //Draw it with polygon to insert UVs for scale - Vector<Vector2> backPoints; - backPoints.push_back(Vector2(x, y)); - backPoints.push_back(Vector2(x, y + h)); - backPoints.push_back(Vector2(x + w, y + h)); - backPoints.push_back(Vector2(x + w, y)); - Vector<Color> colorPoints; - colorPoints.push_back(Color(1, 1, 1, 1)); - colorPoints.push_back(Color(1, 1, 1, 1)); - colorPoints.push_back(Color(1, 1, 1, 1)); - colorPoints.push_back(Color(1, 1, 1, 1)); - Vector<Vector2> uvPoints; - //Draw checker pattern pixel-perfect and scale it by 2. - uvPoints.push_back(Vector2(x, y)); - uvPoints.push_back(Vector2(x, y + h * .5f / checker->get_height())); - uvPoints.push_back(Vector2(x + w * .5f / checker->get_width(), y + h * .5f / checker->get_height())); - uvPoints.push_back(Vector2(x + w * .5f / checker->get_width(), y)); - draw_polygon(backPoints, colorPoints, uvPoints, checker); -} - Size2 GradientEdit::get_minimum_size() const { return Vector2(0, 16); } @@ -439,7 +415,7 @@ void GradientEdit::_color_changed(const Color &p_color) { emit_signal(SNAME("ramp_changed")); } -void GradientEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) { +void GradientEdit::set_ramp(const Vector<real_t> &p_offsets, const Vector<Color> &p_colors) { ERR_FAIL_COND(p_offsets.size() != p_colors.size()); points.clear(); for (int i = 0; i < p_offsets.size(); i++) { @@ -453,8 +429,8 @@ void GradientEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> update(); } -Vector<float> GradientEdit::get_offsets() const { - Vector<float> ret; +Vector<real_t> GradientEdit::get_offsets() const { + Vector<real_t> ret; for (int i = 0; i < points.size(); i++) { ret.push_back(points[i].offset); } diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index eb7367d598..b0ee2c4abb 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -42,8 +42,6 @@ class GradientEdit : public Control { PopupPanel *popup; ColorPicker *picker; - Ref<ImageTexture> checker; - bool grabbing = false; int grabbed = -1; Vector<Gradient::Point> points; @@ -59,8 +57,8 @@ protected: static void _bind_methods(); public: - void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors); - Vector<float> get_offsets() const; + void set_ramp(const Vector<real_t> &p_offsets, const Vector<Color> &p_colors); + Vector<real_t> get_offsets() const; Vector<Color> get_colors() const; void set_points(Vector<Gradient::Point> &p_points); Vector<Gradient::Point> &get_points(); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index fdf6181f1d..258d65112a 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -245,6 +245,7 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].custom_bg = p_custom_bg_color; + update(); } Color ItemList::get_item_custom_bg_color(int p_idx) const { @@ -257,6 +258,7 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo ERR_FAIL_INDEX(p_idx, items.size()); items.write[p_idx].custom_fg = p_custom_fg_color; + update(); } Color ItemList::get_item_custom_fg_color(int p_idx) const { diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index d809fd502f..67323e7f93 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -59,7 +59,7 @@ public: bool outline = false; Point2 offset; Color color; - float elapsed_time = 0.0f; + double elapsed_time = 0.0f; Dictionary environment; uint32_t glpyh_index = 0; RID font; @@ -69,8 +69,8 @@ public: Vector2i get_range() { return range; } void set_range(const Vector2i &p_range) { range = p_range; } - float get_elapsed_time() { return elapsed_time; } - void set_elapsed_time(float p_elapsed_time) { elapsed_time = p_elapsed_time; } + double get_elapsed_time() { return elapsed_time; } + void set_elapsed_time(double p_elapsed_time) { elapsed_time = p_elapsed_time; } bool is_visible() { return visibility; } void set_visibility(bool p_visibility) { visibility = p_visibility; } bool is_outline() { return outline; } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 3925e0c38e..cf2a1481a1 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1323,7 +1323,7 @@ void RichTextLabel::_update_scroll() { } } -void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, float p_delta_time) { +void RichTextLabel::_update_fx(RichTextLabel::ItemFrame *p_frame, double p_delta_time) { Item *it = p_frame; while (it) { ItemFX *ifx = nullptr; @@ -1441,7 +1441,7 @@ void RichTextLabel::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PROCESS: { if (is_visible_in_tree()) { - float dt = get_process_delta_time(); + double dt = get_process_delta_time(); _update_fx(main, dt); update(); } @@ -2289,7 +2289,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub } } -void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, VAlign p_align) { +void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlign p_align) { if (current->type == ITEM_TABLE) { return; } @@ -2534,7 +2534,7 @@ void RichTextLabel::push_meta(const Variant &p_meta) { _add_item(item, true); } -void RichTextLabel::push_table(int p_columns, VAlign p_align) { +void RichTextLabel::push_table(int p_columns, InlineAlign p_align) { ERR_FAIL_COND(p_columns < 1); ItemTable *item = memnew(ItemTable); @@ -2897,18 +2897,35 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { columns = 1; } - VAlign align = VALIGN_TOP; - if (subtag.size() > 1) { + int align = INLINE_ALIGN_TOP; + if (subtag.size() > 2) { if (subtag[1] == "top" || subtag[1] == "t") { - align = VALIGN_TOP; + align = INLINE_ALIGN_TOP_TO; } else if (subtag[1] == "center" || subtag[1] == "c") { - align = VALIGN_CENTER; + align = INLINE_ALIGN_CENTER_TO; } else if (subtag[1] == "bottom" || subtag[1] == "b") { - align = VALIGN_BOTTOM; + align = INLINE_ALIGN_BOTTOM_TO; + } + if (subtag[2] == "top" || subtag[2] == "t") { + align |= INLINE_ALIGN_TO_TOP; + } else if (subtag[2] == "center" || subtag[2] == "c") { + align |= INLINE_ALIGN_TO_CENTER; + } else if (subtag[2] == "baseline" || subtag[2] == "l") { + align |= INLINE_ALIGN_TO_BASELINE; + } else if (subtag[2] == "bottom" || subtag[2] == "b") { + align |= INLINE_ALIGN_TO_BOTTOM; + } + } else if (subtag.size() > 1) { + if (subtag[1] == "top" || subtag[1] == "t") { + align = INLINE_ALIGN_TOP; + } else if (subtag[1] == "center" || subtag[1] == "c") { + align = INLINE_ALIGN_CENTER; + } else if (subtag[1] == "bottom" || subtag[1] == "b") { + align = INLINE_ALIGN_BOTTOM; } } - push_table(columns, align); + push_table(columns, (InlineAlign)align); pos = brk_end + 1; tag_stack.push_front("table"); } else if (tag == "cell") { @@ -3187,15 +3204,34 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { pos = end; tag_stack.push_front(bbcode_name); } else if (tag.begins_with("img")) { - VAlign align = VALIGN_TOP; + int align = INLINE_ALIGN_CENTER; if (tag.begins_with("img=")) { - String al = tag.substr(4, tag.length()); - if (al == "top" || al == "t") { - align = VALIGN_TOP; - } else if (al == "center" || al == "c") { - align = VALIGN_CENTER; - } else if (al == "bottom" || al == "b") { - align = VALIGN_BOTTOM; + Vector<String> subtag = tag.substr(4, tag.length()).split(","); + if (subtag.size() > 1) { + if (subtag[0] == "top" || subtag[0] == "t") { + align = INLINE_ALIGN_TOP_TO; + } else if (subtag[0] == "center" || subtag[0] == "c") { + align = INLINE_ALIGN_CENTER_TO; + } else if (subtag[0] == "bottom" || subtag[0] == "b") { + align = INLINE_ALIGN_BOTTOM_TO; + } + if (subtag[1] == "top" || subtag[1] == "t") { + align |= INLINE_ALIGN_TO_TOP; + } else if (subtag[1] == "center" || subtag[1] == "c") { + align |= INLINE_ALIGN_TO_CENTER; + } else if (subtag[1] == "baseline" || subtag[1] == "l") { + align |= INLINE_ALIGN_TO_BASELINE; + } else if (subtag[1] == "bottom" || subtag[1] == "b") { + align |= INLINE_ALIGN_TO_BOTTOM; + } + } else if (subtag.size() > 0) { + if (subtag[0] == "top" || subtag[0] == "t") { + align = INLINE_ALIGN_TOP; + } else if (subtag[0] == "center" || subtag[0] == "c") { + align = INLINE_ALIGN_CENTER; + } else if (subtag[0] == "bottom" || subtag[0] == "b") { + align = INLINE_ALIGN_BOTTOM; + } } } @@ -3236,7 +3272,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { } } - add_image(texture, width, height, color, align); + add_image(texture, width, height, color, (InlineAlign)align); } pos = end; @@ -3961,7 +3997,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text); ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text); ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text); - ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(VALIGN_TOP)); + ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGN_CENTER)); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line); ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font); @@ -3981,7 +4017,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta); ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline); ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough); - ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP)); + ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(INLINE_ALIGN_TOP)); ClassDB::bind_method(D_METHOD("push_dropcap", "string", "font", "size", "dropcap_margins", "color", "outline_size", "outline_color"), &RichTextLabel::push_dropcap, DEFVAL(Rect2()), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(0, 0, 0, 0))); ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand); ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color); diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 999d8b05fd..28dfe74b08 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -161,7 +161,7 @@ private: struct ItemImage : public Item { Ref<Texture2D> image; - VAlign inline_align = VALIGN_TOP; + InlineAlign inline_align = INLINE_ALIGN_CENTER; Size2 size; Color color; ItemImage() { type = ITEM_IMAGE; } @@ -248,7 +248,7 @@ private: int total_width = 0; int total_height = 0; - VAlign inline_align = VALIGN_TOP; + InlineAlign inline_align = INLINE_ALIGN_TOP; ItemTable() { type = ITEM_TABLE; } }; @@ -260,7 +260,7 @@ private: }; struct ItemFX : public Item { - float elapsed_time = 0.f; + double elapsed_time = 0.f; }; struct ItemShake : public ItemFX { @@ -440,7 +440,7 @@ private: void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack); void _update_scroll(); - void _update_fx(ItemFrame *p_frame, float p_delta_time); + void _update_fx(ItemFrame *p_frame, double p_delta_time); void _scroll_changed(double); void _gui_input(Ref<InputEvent> p_event); @@ -463,7 +463,7 @@ private: public: String get_text(); void add_text(const String &p_text); - void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), VAlign p_align = VALIGN_TOP); + void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlign p_align = INLINE_ALIGN_CENTER); void add_newline(); bool remove_line(const int p_line); void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); @@ -484,7 +484,7 @@ public: void push_indent(int p_level); void push_list(int p_level, ListType p_list, bool p_capitalize); void push_meta(const Variant &p_meta); - void push_table(int p_columns, VAlign p_align = VALIGN_TOP); + void push_table(int p_columns, InlineAlign p_align = INLINE_ALIGN_TOP); void push_fade(int p_start_index, int p_length); void push_shake(int p_strength, float p_rate); void push_wave(float p_frequency, float p_amplitude); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index f1e5574351..cbd5fa7425 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -116,6 +116,9 @@ void Node::_notification(int p_notification) { memdelete(data.path_cache); data.path_cache = nullptr; } + if (data.filename.length()) { + get_multiplayer()->scene_enter_exit_notify(data.filename, this, false); + } } break; case NOTIFICATION_PATH_CHANGED: { if (data.path_cache) { @@ -147,6 +150,10 @@ void Node::_notification(int p_notification) { get_script_instance()->call(SceneStringNames::get_singleton()->_ready); } + if (data.filename.length()) { + ERR_FAIL_COND(!is_inside_tree()); + get_multiplayer()->scene_enter_exit_notify(data.filename, this, true); + } } break; case NOTIFICATION_POSTINITIALIZE: { @@ -705,7 +712,7 @@ bool Node::is_enabled() const { return _is_enabled(); } -float Node::get_physics_process_delta_time() const { +double Node::get_physics_process_delta_time() const { if (data.tree) { return data.tree->get_physics_process_time(); } else { @@ -713,7 +720,7 @@ float Node::get_physics_process_delta_time() const { } } -float Node::get_process_delta_time() const { +double Node::get_process_delta_time() const { if (data.tree) { return data.tree->get_process_time(); } else { diff --git a/scene/main/node.h b/scene/main/node.h index 0a88553ea1..9997f4e055 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -202,6 +202,7 @@ protected: static String _get_name_num_separator(); friend class SceneState; + friend class MultiplayerAPI; void _add_child_nocheck(Node *p_child, const StringName &p_name); void _set_owner_nocheck(Node *p_owner); @@ -339,11 +340,11 @@ public: /* PROCESSING */ void set_physics_process(bool p_process); - float get_physics_process_delta_time() const; + double get_physics_process_delta_time() const; bool is_physics_processing() const; void set_process(bool p_process); - float get_process_delta_time() const; + double get_process_delta_time() const; bool is_processing() const; void set_physics_process_internal(bool p_process_internal); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index b5c49a8a97..c836f50bf2 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -375,7 +375,7 @@ private: Variant drag_data; ObjectID drag_preview_id; Ref<SceneTreeTimer> tooltip_timer; - float tooltip_delay = 0.0; + double tooltip_delay = 0.0; Transform2D focus_inv_xform; bool roots_order_dirty = false; List<Control *> roots; diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 640ec50eb9..e6a74e7685 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -77,17 +77,17 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } else if (what == "keys" || what == "key_values") { if (track_get_type(track) == TYPE_TRANSFORM3D) { TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]); - Vector<float> values = p_value; + Vector<real_t> values = p_value; int vcount = values.size(); - ERR_FAIL_COND_V(vcount % 12, false); // should be multiple of 11 + ERR_FAIL_COND_V(vcount % 12, false); // should be multiple of 12 - const float *r = values.ptr(); + const real_t *r = values.ptr(); tt->transforms.resize(vcount / 12); for (int i = 0; i < (vcount / 12); i++) { TKey<TransformKey> &tk = tt->transforms.write[i]; - const float *ofs = &r[i * 12]; + const real_t *ofs = &r[i * 12]; tk.time = ofs[0]; tk.transition = ofs[1]; @@ -125,7 +125,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { vt->update_mode = UpdateMode(um); } - Vector<float> times = d["times"]; + Vector<real_t> times = d["times"]; Array values = d["values"]; ERR_FAIL_COND_V(times.size() != values.size(), false); @@ -133,7 +133,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (times.size()) { int valcount = times.size(); - const float *rt = times.ptr(); + const real_t *rt = times.ptr(); vt->values.resize(valcount); @@ -143,10 +143,10 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } if (d.has("transitions")) { - Vector<float> transitions = d["transitions"]; + Vector<real_t> transitions = d["transitions"]; ERR_FAIL_COND_V(transitions.size() != valcount, false); - const float *rtr = transitions.ptr(); + const real_t *rtr = transitions.ptr(); for (int i = 0; i < valcount; i++) { vt->values.write[i].transition = rtr[i]; @@ -165,7 +165,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!d.has("times"), false); ERR_FAIL_COND_V(!d.has("values"), false); - Vector<float> times = d["times"]; + Vector<real_t> times = d["times"]; Array values = d["values"]; ERR_FAIL_COND_V(times.size() != values.size(), false); @@ -173,17 +173,17 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (times.size()) { int valcount = times.size(); - const float *rt = times.ptr(); + const real_t *rt = times.ptr(); for (int i = 0; i < valcount; i++) { track_insert_key(track, rt[i], values[i]); } if (d.has("transitions")) { - Vector<float> transitions = d["transitions"]; + Vector<real_t> transitions = d["transitions"]; ERR_FAIL_COND_V(transitions.size() != valcount, false); - const float *rtr = transitions.ptr(); + const real_t *rtr = transitions.ptr(); for (int i = 0; i < valcount; i++) { track_set_key_transition(track, i, rtr[i]); @@ -196,16 +196,16 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!d.has("times"), false); ERR_FAIL_COND_V(!d.has("points"), false); - Vector<float> times = d["times"]; - PackedFloat32Array values = d["points"]; + Vector<real_t> times = d["times"]; + Vector<real_t> values = d["points"]; ERR_FAIL_COND_V(times.size() * 5 != values.size(), false); if (times.size()) { int valcount = times.size(); - const float *rt = times.ptr(); - const float *rv = values.ptr(); + const real_t *rt = times.ptr(); + const real_t *rv = values.ptr(); bt->values.resize(valcount); @@ -227,7 +227,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!d.has("times"), false); ERR_FAIL_COND_V(!d.has("clips"), false); - Vector<float> times = d["times"]; + Vector<real_t> times = d["times"]; Array clips = d["clips"]; ERR_FAIL_COND_V(clips.size() != times.size(), false); @@ -235,7 +235,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (times.size()) { int valcount = times.size(); - const float *rt = times.ptr(); + const real_t *rt = times.ptr(); ad->values.clear(); @@ -268,7 +268,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { ERR_FAIL_COND_V(!d.has("times"), false); ERR_FAIL_COND_V(!d.has("clips"), false); - Vector<float> times = d["times"]; + Vector<real_t> times = d["times"]; Vector<String> clips = d["clips"]; ERR_FAIL_COND_V(clips.size() != times.size(), false); @@ -276,7 +276,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (times.size()) { int valcount = times.size(); - const float *rt = times.ptr(); + const real_t *rt = times.ptr(); const String *rc = clips.ptr(); an->values.resize(valcount); @@ -352,9 +352,9 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { r_ret = track_is_enabled(track); } else if (what == "keys") { if (track_get_type(track) == TYPE_TRANSFORM3D) { - Vector<float> keys; + Vector<real_t> keys; int kk = track_get_key_count(track); - keys.resize(kk * 12); + keys.resize(kk * sizeof(Transform3D)); real_t *w = keys.ptrw(); @@ -389,8 +389,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { Dictionary d; - Vector<float> key_times; - Vector<float> key_transitions; + Vector<real_t> key_times; + Vector<real_t> key_transitions; Array key_values; int kk = vt->values.size(); @@ -399,8 +399,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { key_transitions.resize(kk); key_values.resize(kk); - float *wti = key_times.ptrw(); - float *wtr = key_transitions.ptrw(); + real_t *wti = key_times.ptrw(); + real_t *wtr = key_transitions.ptrw(); int idx = 0; @@ -427,8 +427,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { } else if (track_get_type(track) == TYPE_METHOD) { Dictionary d; - Vector<float> key_times; - Vector<float> key_transitions; + Vector<real_t> key_times; + Vector<real_t> key_transitions; Array key_values; int kk = track_get_key_count(track); @@ -437,8 +437,8 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { key_transitions.resize(kk); key_values.resize(kk); - float *wti = key_times.ptrw(); - float *wtr = key_transitions.ptrw(); + real_t *wti = key_times.ptrw(); + real_t *wtr = key_transitions.ptrw(); int idx = 0; for (int i = 0; i < track_get_key_count(track); i++) { @@ -463,16 +463,16 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { Dictionary d; - Vector<float> key_times; - Vector<float> key_points; + Vector<real_t> key_times; + Vector<real_t> key_points; int kk = bt->values.size(); key_times.resize(kk); key_points.resize(kk * 5); - float *wti = key_times.ptrw(); - float *wpo = key_points.ptrw(); + real_t *wti = key_times.ptrw(); + real_t *wpo = key_points.ptrw(); int idx = 0; @@ -499,14 +499,14 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { Dictionary d; - Vector<float> key_times; + Vector<real_t> key_times; Array clips; int kk = ad->values.size(); key_times.resize(kk); - float *wti = key_times.ptrw(); + real_t *wti = key_times.ptrw(); int idx = 0; @@ -533,7 +533,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { Dictionary d; - Vector<float> key_times; + Vector<real_t> key_times; Vector<String> clips; int kk = an->values.size(); @@ -541,7 +541,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { key_times.resize(kk); clips.resize(kk); - float *wti = key_times.ptrw(); + real_t *wti = key_times.ptrw(); String *wcl = clips.ptrw(); const TKey<StringName> *vls = an->values.ptr(); @@ -722,7 +722,7 @@ bool Animation::track_get_interpolation_loop_wrap(int p_track) const { // transform /* template<class T> -int Animation::_insert_pos(float p_time, T& p_keys) { +int Animation::_insert_pos(double p_time, T& p_keys) { // simple, linear time inset that should be fast enough in reality. int idx=p_keys.size(); @@ -745,12 +745,12 @@ int Animation::_insert_pos(float p_time, T& p_keys) { */ template <class T, class V> -int Animation::_insert(float p_time, T &p_keys, const V &p_value) { +int Animation::_insert(double p_time, T &p_keys, const V &p_value) { int idx = p_keys.size(); while (true) { // Condition for replacement. - if (idx > 0 && Math::is_equal_approx(p_keys[idx - 1].time, p_time)) { + if (idx > 0 && Math::is_equal_approx((double)p_keys[idx - 1].time, p_time)) { float transition = p_keys[idx - 1].transition; p_keys.write[idx - 1] = p_value; p_keys.write[idx - 1].transition = transition; @@ -794,7 +794,7 @@ Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, return OK; } -int Animation::transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quaternion &p_rot, const Vector3 &p_scale) { +int Animation::transform_track_insert_key(int p_track, double p_time, const Vector3 &p_loc, const Quaternion &p_rot, const Vector3 &p_scale) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, -1); @@ -812,7 +812,7 @@ int Animation::transform_track_insert_key(int p_track, float p_time, const Vecto return ret; } -void Animation::track_remove_key_at_time(int p_track, float p_time) { +void Animation::track_remove_key_at_time(int p_track, double p_time) { int idx = track_find_key(p_track, p_time, true); ERR_FAIL_COND(idx < 0); track_remove_key(p_track, idx); @@ -864,7 +864,7 @@ void Animation::track_remove_key(int p_track, int p_idx) { emit_changed(); } -int Animation::track_find_key(int p_track, float p_time, bool p_exact) const { +int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; @@ -946,7 +946,7 @@ int Animation::track_find_key(int p_track, float p_time, bool p_exact) const { return -1; } -void Animation::track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition) { +void Animation::track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; @@ -1151,7 +1151,7 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { ERR_FAIL_V(Variant()); } -float Animation::track_get_key_time(int p_track, int p_key_idx) const { +double Animation::track_get_key_time(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; @@ -1196,7 +1196,7 @@ float Animation::track_get_key_time(int p_track, int p_key_idx) const { ERR_FAIL_V(-1); } -void Animation::track_set_key_time(int p_track, int p_key_idx, float p_time) { +void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; @@ -1260,7 +1260,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, float p_time) { ERR_FAIL(); } -float Animation::track_get_key_transition(int p_track, int p_key_idx) const { +real_t Animation::track_get_key_transition(int p_track, int p_key_idx) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; @@ -1379,7 +1379,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p emit_changed(); } -void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_transition) { +void Animation::track_set_key_transition(int p_track, int p_key_idx, real_t p_transition) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; @@ -1412,7 +1412,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra } template <class K> -int Animation::_find(const Vector<K> &p_keys, float p_time) const { +int Animation::_find(const Vector<K> &p_keys, double p_time) const { int len = p_keys.size(); if (len == 0) { return -2; @@ -1433,7 +1433,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const { while (low <= high) { middle = (low + high) / 2; - if (Math::is_equal_approx(p_time, keys[middle].time)) { //match + if (Math::is_equal_approx(p_time, (double)keys[middle].time)) { //match return middle; } else if (p_time < keys[middle].time) { high = middle - 1; //search low end of array @@ -1449,7 +1449,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const { return middle; } -Animation::TransformKey Animation::_interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, float p_c) const { +Animation::TransformKey Animation::_interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const { TransformKey ret; ret.loc = _interpolate(p_a.loc, p_b.loc, p_c); ret.rot = _interpolate(p_a.rot, p_b.rot, p_c); @@ -1458,25 +1458,25 @@ Animation::TransformKey Animation::_interpolate(const Animation::TransformKey &p return ret; } -Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_c) const { +Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const { return p_a.lerp(p_b, p_c); } -Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b, float p_c) const { +Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const { return p_a.slerp(p_b, p_c); } -Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, float p_c) const { +Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const { Variant dst; Variant::interpolate(p_a, p_b, p_c, dst); return dst; } -float Animation::_interpolate(const float &p_a, const float &p_b, float p_c) const { +real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const { return p_a * (1.0 - p_c) + p_b * p_c; } -Animation::TransformKey Animation::_cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, float p_c) const { +Animation::TransformKey Animation::_cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, real_t p_c) const { Animation::TransformKey tk; tk.loc = p_a.loc.cubic_interpolate(p_b.loc, p_pre_a.loc, p_post_b.loc, p_c); @@ -1486,15 +1486,15 @@ Animation::TransformKey Animation::_cubic_interpolate(const Animation::Transform return tk; } -Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, float p_c) const { +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, float p_c) const { +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.cubic_slerp(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, float p_c) const { +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(); @@ -1515,9 +1515,9 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a real_t p2 = p_b; real_t p3 = p_post_b; - float t = p_c; - float t2 = t * t; - float t3 = t2 * t; + real_t t = p_c; + real_t t2 = t * t; + real_t t3 = t2 * t; return 0.5f * ((p1 * 2.0f) + (-p0 + p2) * t + @@ -1579,12 +1579,12 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a } } -float Animation::_cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const { +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); } template <class T> -T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const { +T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const { int len = _find(p_keys, length) + 1; // try to find last key (there may be more past the end) if (len <= 0) { @@ -1608,7 +1608,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola bool result = true; int next = 0; - float c = 0.0; + real_t c = 0.0; // prepare for all cases of interpolation if (loop && p_loop_wrap) { @@ -1616,8 +1616,8 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola if (idx >= 0) { if ((idx + 1) < len) { next = idx + 1; - float delta = p_keys[next].time - p_keys[idx].time; - float from = p_time - p_keys[idx].time; + real_t delta = p_keys[next].time - p_keys[idx].time; + real_t from = p_time - p_keys[idx].time; if (Math::is_zero_approx(delta)) { c = 0; @@ -1627,8 +1627,8 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola } else { next = 0; - float delta = (length - p_keys[idx].time) + p_keys[next].time; - float from = p_time - p_keys[idx].time; + real_t delta = (length - p_keys[idx].time) + p_keys[next].time; + real_t from = p_time - p_keys[idx].time; if (Math::is_zero_approx(delta)) { c = 0; @@ -1641,12 +1641,12 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola // on loop, behind first key idx = len - 1; next = 0; - float endtime = (length - p_keys[idx].time); + real_t endtime = (length - p_keys[idx].time); if (endtime < 0) { // may be keys past the end endtime = 0; } - float delta = endtime + p_keys[next].time; - float from = endtime + p_time; + real_t delta = endtime + p_keys[next].time; + real_t from = endtime + p_time; if (Math::is_zero_approx(delta)) { c = 0; @@ -1660,8 +1660,8 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola if (idx >= 0) { if ((idx + 1) < len) { next = idx + 1; - float delta = p_keys[next].time - p_keys[idx].time; - float from = p_time - p_keys[idx].time; + real_t delta = p_keys[next].time - p_keys[idx].time; + real_t from = p_time - p_keys[idx].time; if (Math::is_zero_approx(delta)) { c = 0; @@ -1690,7 +1690,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola return T(); } - float tr = p_keys[idx].transition; + real_t tr = p_keys[idx].transition; if (tr == 0 || idx == next) { // don't interpolate if not needed @@ -1728,7 +1728,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola // do a barrel roll } -Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { +Error Animation::transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); @@ -1758,7 +1758,7 @@ Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 return OK; } -Variant Animation::value_track_interpolate(int p_track, float p_time) const { +Variant Animation::value_track_interpolate(int p_track, double p_time) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_VALUE, Variant()); @@ -1775,7 +1775,7 @@ Variant Animation::value_track_interpolate(int p_track, float p_time) const { return Variant(); } -void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const { +void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) { to_time = length * 1.001; //include a little more if at the end } @@ -1812,15 +1812,15 @@ void Animation::_value_track_get_key_indices_in_range(const ValueTrack *vt, floa } } -void Animation::value_track_get_key_indices(int p_track, float p_time, float p_delta, List<int> *p_indices) const { +void Animation::value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_VALUE); ValueTrack *vt = static_cast<ValueTrack *>(t); - float from_time = p_time - p_delta; - float to_time = p_time; + double from_time = p_time - p_delta; + double to_time = p_time; if (from_time > to_time) { SWAP(from_time, to_time); @@ -1875,7 +1875,7 @@ Animation::UpdateMode Animation::value_track_get_update_mode(int p_track) const } template <class T> -void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, float from_time, float to_time, List<int> *p_indices) const { +void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) { to_time = length * 1.01; //include a little more if at the end } @@ -1908,12 +1908,12 @@ void Animation::_track_get_key_indices_in_range(const Vector<T> &p_array, float } } -void Animation::track_get_key_indices_in_range(int p_track, float p_time, float p_delta, List<int> *p_indices) const { +void Animation::track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices) const { ERR_FAIL_INDEX(p_track, tracks.size()); const Track *t = tracks[p_track]; - float from_time = p_time - p_delta; - float to_time = p_time; + double from_time = p_time - p_delta; + double to_time = p_time; if (from_time > to_time) { SWAP(from_time, to_time); @@ -2021,7 +2021,7 @@ void Animation::track_get_key_indices_in_range(int p_track, float p_time, float } } -void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const { +void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const { if (from_time != length && to_time == length) { to_time = length * 1.01; //include a little more if at the end } @@ -2054,15 +2054,15 @@ void Animation::_method_track_get_key_indices_in_range(const MethodTrack *mt, fl } } -void Animation::method_track_get_key_indices(int p_track, float p_time, float p_delta, List<int> *p_indices) const { +void Animation::method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_METHOD); MethodTrack *mt = static_cast<MethodTrack *>(t); - float from_time = p_time - p_delta; - float to_time = p_time; + double from_time = p_time - p_delta; + double to_time = p_time; if (from_time > to_time) { SWAP(from_time, to_time); @@ -2128,7 +2128,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, float p_time, float p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle) { +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); @@ -2154,7 +2154,7 @@ int Animation::bezier_track_insert_key(int p_track, float p_time, float p_value, return key; } -void Animation::bezier_track_set_key_value(int p_track, int p_index, float p_value) { +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]; ERR_FAIL_COND(t->type != TYPE_BEZIER); @@ -2199,7 +2199,7 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const emit_changed(); } -float Animation::bezier_track_get_key_value(int p_track, int p_index) const { +real_t Animation::bezier_track_get_key_value(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); @@ -2246,7 +2246,7 @@ static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, const Vector2 &start, con return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3; } -float Animation::bezier_track_interpolate(int p_track, float p_time) const { +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); Track *track = tracks[p_track]; @@ -2277,14 +2277,14 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const { return bt->values[bt->values.size() - 1].value.value; } - float t = p_time - bt->values[idx].time; + double t = p_time - bt->values[idx].time; int iterations = 10; - float duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes - float low = 0.0; // 0% of the current animation segment - float high = 1.0; // 100% of the current animation segment - float middle; + real_t duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes + real_t low = 0.0; // 0% of the current animation segment + real_t high = 1.0; // 100% of the current animation segment + real_t middle; Vector2 start(0, bt->values[idx].value.value); Vector2 start_out = start + bt->values[idx].value.out_handle; @@ -2307,12 +2307,12 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const { //interpolate the result: Vector2 low_pos = _bezier_interp(low, start, start_out, end_in, end); Vector2 high_pos = _bezier_interp(high, start, start_out, end_in, end); - float c = (t - low_pos.x) / (high_pos.x - low_pos.x); + real_t c = (t - low_pos.x) / (high_pos.x - low_pos.x); return low_pos.lerp(high_pos, c).y; } -int Animation::audio_track_insert_key(int p_track, float p_time, const RES &p_stream, float p_start_offset, float p_end_offset) { +int Animation::audio_track_insert_key(int p_track, double p_time, const RES &p_stream, real_t p_start_offset, real_t p_end_offset) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_AUDIO, -1); @@ -2352,7 +2352,7 @@ void Animation::audio_track_set_key_stream(int p_track, int p_key, const RES &p_ emit_changed(); } -void Animation::audio_track_set_key_start_offset(int p_track, int p_key, float p_offset) { +void Animation::audio_track_set_key_start_offset(int p_track, int p_key, real_t p_offset) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_AUDIO); @@ -2370,7 +2370,7 @@ void Animation::audio_track_set_key_start_offset(int p_track, int p_key, float p emit_changed(); } -void Animation::audio_track_set_key_end_offset(int p_track, int p_key, float p_offset) { +void Animation::audio_track_set_key_end_offset(int p_track, int p_key, real_t p_offset) { ERR_FAIL_INDEX(p_track, tracks.size()); Track *t = tracks[p_track]; ERR_FAIL_COND(t->type != TYPE_AUDIO); @@ -2400,7 +2400,7 @@ RES Animation::audio_track_get_key_stream(int p_track, int p_key) const { return at->values[p_key].value.stream; } -float Animation::audio_track_get_key_start_offset(int p_track, int p_key) const { +real_t Animation::audio_track_get_key_start_offset(int p_track, int p_key) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); const Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_AUDIO, 0); @@ -2412,7 +2412,7 @@ float Animation::audio_track_get_key_start_offset(int p_track, int p_key) const return at->values[p_key].value.start_offset; } -float Animation::audio_track_get_key_end_offset(int p_track, int p_key) const { +real_t Animation::audio_track_get_key_end_offset(int p_track, int p_key) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), 0); const Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_AUDIO, 0); @@ -2426,7 +2426,7 @@ float Animation::audio_track_get_key_end_offset(int p_track, int p_key) const { // -int Animation::animation_track_insert_key(int p_track, float p_time, const StringName &p_animation) { +int Animation::animation_track_insert_key(int p_track, double p_time, const StringName &p_animation) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; ERR_FAIL_COND_V(t->type != TYPE_ANIMATION, -1); @@ -2470,7 +2470,7 @@ StringName Animation::animation_track_get_key_animation(int p_track, int p_key) return at->values[p_key].value; } -void Animation::set_length(float p_length) { +void Animation::set_length(real_t p_length) { if (p_length < ANIM_MIN_LENGTH) { p_length = ANIM_MIN_LENGTH; } @@ -2478,7 +2478,7 @@ void Animation::set_length(float p_length) { emit_changed(); } -float Animation::get_length() const { +real_t Animation::get_length() const { return length; } @@ -2558,12 +2558,12 @@ void Animation::track_swap(int p_track, int p_with_track) { emit_signal(SceneStringNames::get_singleton()->tracks_changed); } -void Animation::set_step(float p_step) { +void Animation::set_step(real_t p_step) { step = p_step; emit_changed(); } -float Animation::get_step() const { +real_t Animation::get_step() const { return step; } @@ -2708,7 +2708,7 @@ void Animation::clear() { emit_signal(SceneStringNames::get_singleton()->tracks_changed); } -bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err, float p_alowed_angular_err, float p_max_optimizable_angle, const Vector3 &p_norm) { +bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, real_t p_alowed_linear_err, real_t p_alowed_angular_err, real_t p_max_optimizable_angle, const Vector3 &p_norm) { real_t c = (t1.time - t0.time) / (t2.time - t0.time); real_t t[3] = { -1, -1, -1 }; @@ -2727,9 +2727,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons } else { Vector3 pd = (v2 - v0); - float d0 = pd.dot(v0); - float d1 = pd.dot(v1); - float d2 = pd.dot(v2); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); if (d1 < d0 || d1 > d2) { return false; } @@ -2817,9 +2817,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons } else { Vector3 pd = (v2 - v0); - float d0 = pd.dot(v0); - float d1 = pd.dot(v1); - float d2 = pd.dot(v2); + real_t d0 = pd.dot(v0); + real_t d1 = pd.dot(v1); + real_t d2 = pd.dot(v2); if (d1 < d0 || d1 > d2) { return false; //beyond segment range } @@ -2875,7 +2875,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons return erase; } -void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err, float p_allowed_angular_err, float p_max_optimizable_angle) { +void Animation::_transform_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { ERR_FAIL_INDEX(p_idx, tracks.size()); ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM3D); TransformTrack *tt = static_cast<TransformTrack *>(tracks[p_idx]); @@ -2915,7 +2915,7 @@ void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err, } } -void Animation::optimize(float p_allowed_linear_err, float p_allowed_angular_err, float p_max_optimizable_angle) { +void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) { for (int i = 0; i < tracks.size(); i++) { if (tracks[i]->type == TYPE_TRANSFORM3D) { _transform_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 920ee2e5ab..6227f6967f 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -76,8 +76,8 @@ private: }; struct Key { - float transition = 1.0; - float time = 0.0; // time in secs + real_t transition = 1.0; + double time = 0.0; // time in secs }; // transform key holds either Vector3 or Quaternion @@ -129,7 +129,7 @@ private: struct BezierKey { Vector2 in_handle; //relative (x always <0) Vector2 out_handle; //relative (x always >0) - float value = 0.0; + real_t value = 0.0; }; struct BezierTrack : public Track { @@ -144,8 +144,8 @@ private: struct AudioKey { RES stream; - float start_offset = 0.0; //offset from start - float end_offset = 0.0; //offset from end, if 0 then full length or infinite + real_t start_offset = 0.0; //offset from start + real_t end_offset = 0.0; //offset from end, if 0 then full length or infinite AudioKey() { } }; @@ -172,46 +172,46 @@ private: /* template<class T> - int _insert_pos(float p_time, T& p_keys);*/ + int _insert_pos(double p_time, T& p_keys);*/ template <class T> void _clear(T &p_keys); template <class T, class V> - int _insert(float p_time, T &p_keys, const V &p_value); + int _insert(double p_time, T &p_keys, const V &p_value); template <class K> - inline int _find(const Vector<K> &p_keys, float p_time) const; + inline int _find(const Vector<K> &p_keys, double p_time) const; - _FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, float p_c) const; + _FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, real_t p_c) const; - _FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_c) const; - _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, float p_c) const; - _FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, float p_c) const; - _FORCE_INLINE_ float _interpolate(const float &p_a, const float &p_b, float p_c) const; + _FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const; + _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const; + _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_ Animation::TransformKey _cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, float 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, float 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, float 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, float p_c) const; - _FORCE_INLINE_ float _cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const; + _FORCE_INLINE_ Animation::TransformKey _cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_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; template <class T> - _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, float p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const; + _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok) const; template <class T> - _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, float from_time, float to_time, List<int> *p_indices) const; + _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices) const; - _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const; - _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const; + _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, double from_time, double to_time, List<int> *p_indices) const; + _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, double from_time, double to_time, List<int> *p_indices) const; - float length = 1.0; - float step = 0.1; + double length = 1.0; + real_t step = 0.1; bool loop = false; // bind helpers private: - Array _transform_track_interpolate(int p_track, float p_time) const { + Array _transform_track_interpolate(int p_track, double p_time) const { Vector3 loc; Quaternion rot; Vector3 scale; @@ -223,7 +223,7 @@ private: return ret; } - Vector<int> _value_track_get_key_indices(int p_track, float p_time, float p_delta) const { + Vector<int> _value_track_get_key_indices(int p_track, double p_time, double p_delta) const { List<int> idxs; value_track_get_key_indices(p_track, p_time, p_delta, &idxs); Vector<int> idxr; @@ -233,7 +233,7 @@ private: } return idxr; } - Vector<int> _method_track_get_key_indices(int p_track, float p_time, float p_delta) const { + Vector<int> _method_track_get_key_indices(int p_track, double p_time, double p_delta) const { List<int> idxs; method_track_get_key_indices(p_track, p_time, p_delta, &idxs); Vector<int> idxr; @@ -244,8 +244,8 @@ private: return idxr; } - bool _transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err, float p_alowed_angular_err, float p_max_optimizable_angle, const Vector3 &p_norm); - void _transform_track_optimize(int p_idx, float p_allowed_linear_err = 0.05, float p_allowed_angular_err = 0.01, float p_max_optimizable_angle = Math_PI * 0.125); + bool _transform_track_optimize_key(const TKey<TransformKey> &t0, const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, real_t p_alowed_linear_err, real_t p_alowed_angular_err, real_t p_max_optimizable_angle, const Vector3 &p_norm); + void _transform_track_optimize(int p_idx, real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125); protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -279,75 +279,75 @@ public: void track_set_enabled(int p_track, bool p_enabled); bool track_is_enabled(int p_track) const; - void track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition = 1); - void track_set_key_transition(int p_track, int p_key_idx, float p_transition); + void track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition = 1); + void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition); void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); - void track_set_key_time(int p_track, int p_key_idx, float p_time); - int track_find_key(int p_track, float p_time, bool p_exact = false) const; + void track_set_key_time(int p_track, int p_key_idx, double p_time); + int track_find_key(int p_track, double p_time, bool p_exact = false) const; void track_remove_key(int p_track, int p_idx); - void track_remove_key_at_time(int p_track, float p_time); + void track_remove_key_at_time(int p_track, double p_time); int track_get_key_count(int p_track) const; Variant track_get_key_value(int p_track, int p_key_idx) const; - float track_get_key_time(int p_track, int p_key_idx) const; - float track_get_key_transition(int p_track, int p_key_idx) const; + double track_get_key_time(int p_track, int p_key_idx) const; + real_t track_get_key_transition(int p_track, int p_key_idx) const; - int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quaternion &p_rot = Quaternion(), const Vector3 &p_scale = Vector3()); + int transform_track_insert_key(int p_track, double p_time, const Vector3 &p_loc, const Quaternion &p_rot = Quaternion(), const Vector3 &p_scale = Vector3()); Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; 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, float p_time, float p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle); - void bezier_track_set_key_value(int p_track, int p_index, float p_value); + 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); void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle); - float bezier_track_get_key_value(int p_track, int p_index) const; + real_t bezier_track_get_key_value(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; - float bezier_track_interpolate(int p_track, float p_time) const; + real_t bezier_track_interpolate(int p_track, double p_time) const; - int audio_track_insert_key(int p_track, float p_time, const RES &p_stream, float p_start_offset = 0, float p_end_offset = 0); + int audio_track_insert_key(int p_track, double p_time, const RES &p_stream, real_t p_start_offset = 0, real_t p_end_offset = 0); void audio_track_set_key_stream(int p_track, int p_key, const RES &p_stream); - void audio_track_set_key_start_offset(int p_track, int p_key, float p_offset); - void audio_track_set_key_end_offset(int p_track, int p_key, float p_offset); + void audio_track_set_key_start_offset(int p_track, int p_key, real_t p_offset); + void audio_track_set_key_end_offset(int p_track, int p_key, real_t p_offset); RES audio_track_get_key_stream(int p_track, int p_key) const; - float audio_track_get_key_start_offset(int p_track, int p_key) const; - float audio_track_get_key_end_offset(int p_track, int p_key) const; + real_t audio_track_get_key_start_offset(int p_track, int p_key) const; + real_t audio_track_get_key_end_offset(int p_track, int p_key) const; - int animation_track_insert_key(int p_track, float p_time, const StringName &p_animation); + int animation_track_insert_key(int p_track, double p_time, const StringName &p_animation); void animation_track_set_key_animation(int p_track, int p_key, const StringName &p_animation); StringName animation_track_get_key_animation(int p_track, int p_key) const; void track_set_interpolation_loop_wrap(int p_track, bool p_enable); bool track_get_interpolation_loop_wrap(int p_track) const; - Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; + Error transform_track_interpolate(int p_track, double p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; - Variant value_track_interpolate(int p_track, float p_time) const; - void value_track_get_key_indices(int p_track, float p_time, float p_delta, List<int> *p_indices) const; + Variant value_track_interpolate(int p_track, double p_time) const; + void value_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const; void value_track_set_update_mode(int p_track, UpdateMode p_mode); UpdateMode value_track_get_update_mode(int p_track) const; - void method_track_get_key_indices(int p_track, float p_time, float p_delta, List<int> *p_indices) const; + void method_track_get_key_indices(int p_track, double p_time, double p_delta, List<int> *p_indices) const; Vector<Variant> method_track_get_params(int p_track, int p_key_idx) const; StringName method_track_get_name(int p_track, int p_key_idx) const; void copy_track(int p_track, Ref<Animation> p_to_animation); - void track_get_key_indices_in_range(int p_track, float p_time, float p_delta, List<int> *p_indices) const; + void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices) const; - void set_length(float p_length); - float get_length() const; + void set_length(real_t p_length); + real_t get_length() const; void set_loop(bool p_enabled); bool has_loop() const; - void set_step(float p_step); - float get_step() const; + void set_step(real_t p_step); + real_t get_step() const; void clear(); - void optimize(float p_allowed_linear_err = 0.05, float p_allowed_angular_err = 0.01, float p_max_optimizable_angle = Math_PI * 0.125); + void optimize(real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125); Animation(); ~Animation(); diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 8ffd2df112..ef070589e4 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -261,11 +261,11 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in sign = -1; } - float global_rate_scale = AudioServer::get_singleton()->get_global_rate_scale(); - float base_rate = AudioServer::get_singleton()->get_mix_rate() * global_rate_scale; + float base_rate = AudioServer::get_singleton()->get_mix_rate(); float srate = base->mix_rate; srate *= p_rate_scale; - float fincrement = srate / base_rate; + float playback_speed_scale = AudioServer::get_singleton()->get_playback_speed_scale(); + float fincrement = (srate * playback_speed_scale) / base_rate; int32_t increment = int32_t(MAX(fincrement * MIX_FRAC_LEN, 1)); increment *= sign; diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index c13db83d6d..3b666640f8 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -1366,7 +1366,7 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const { frac /= bake_interval; } - return Math::lerp(r[idx], r[idx + 1], frac); + return Math::lerp(r[idx], r[idx + 1], (real_t)frac); } Vector3 Curve3D::interpolate_baked_up_vector(float p_offset, bool p_apply_tilt) const { @@ -1424,7 +1424,7 @@ PackedVector3Array Curve3D::get_baked_points() const { return baked_point_cache; } -PackedFloat32Array Curve3D::get_baked_tilts() const { +Vector<real_t> Curve3D::get_baked_tilts() const { if (baked_cache_dirty) { _bake(); } @@ -1545,7 +1545,7 @@ Dictionary Curve3D::_get_data() const { PackedVector3Array d; d.resize(points.size() * 3); Vector3 *w = d.ptrw(); - PackedFloat32Array t; + Vector<real_t> t; t.resize(points.size()); real_t *wt = t.ptrw(); @@ -1571,7 +1571,7 @@ void Curve3D::_set_data(const Dictionary &p_data) { ERR_FAIL_COND(pc % 3 != 0); points.resize(pc / 3); const Vector3 *r = rp.ptr(); - PackedFloat32Array rtl = p_data["tilts"]; + Vector<real_t> rtl = p_data["tilts"]; const real_t *rt = rtl.ptr(); for (int i = 0; i < points.size(); i++) { diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 746c6fa597..c25d307608 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -222,7 +222,7 @@ class Curve3D : public Resource { mutable bool baked_cache_dirty = false; mutable PackedVector3Array baked_point_cache; - mutable PackedFloat32Array baked_tilt_cache; + mutable Vector<real_t> baked_tilt_cache; mutable PackedVector3Array baked_up_vector_cache; mutable float baked_max_ofs = 0.0; @@ -265,7 +265,7 @@ public: float interpolate_baked_tilt(float p_offset) const; Vector3 interpolate_baked_up_vector(float p_offset, bool p_apply_tilt = false) const; PackedVector3Array get_baked_points() const; //useful for going through - PackedFloat32Array get_baked_tilts() const; //useful for going through + Vector<real_t> get_baked_tilts() const; //useful for going through PackedVector3Array get_baked_up_vectors() const; Vector3 get_closest_point(const Vector3 &p_to_point) const; float get_closest_offset(const Vector3 &p_to_point) const; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index d0dee2b5e3..efc37709a5 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -863,6 +863,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("bar_arrow", "ColorPicker", make_icon(bar_arrow_png)); theme->set_icon("picker_cursor", "ColorPicker", make_icon(picker_cursor_png)); + // ColorPickerButton + theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png)); // TooltipPanel diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index cdb1bc527b..97e64e4746 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -50,10 +50,6 @@ static const unsigned char checked_disabled_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x73, 0x72, 0x7b, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x82, 0x80, 0x8a, 0x90, 0x90, 0x93, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x93, 0x93, 0x95, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x7d, 0x7d, 0x7f, 0x58, 0x58, 0x5b, 0xa4, 0xa4, 0xa4, 0x9e, 0x9e, 0xa0, 0x9e, 0x9e, 0x9e, 0x9b, 0x9b, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x93, 0x93, 0x94, 0x8f, 0x8f, 0x8f, 0x86, 0x86, 0x88, 0x85, 0x85, 0x86, 0x82, 0x82, 0x83, 0x81, 0x81, 0x83, 0x7f, 0x7f, 0x81, 0x7c, 0x7c, 0x7e, 0x7a, 0x7a, 0x7d, 0x78, 0x78, 0x7b, 0x71, 0x71, 0x74, 0x68, 0x68, 0x6c, 0x66, 0x66, 0x6a, 0x65, 0x65, 0x68, 0x63, 0x63, 0x66, 0x5f, 0x5f, 0x63, 0x5c, 0x5c, 0x60, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x59, 0x59, 0x5c, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x10, 0x13, 0xbb, 0xf, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xb4, 0xdd, 0xfa, 0xfa, 0xfb, 0xfb, 0x5b, 0xd1, 0xf1, 0xe6, 0x0, 0x0, 0x0, 0x96, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x5d, 0x8f, 0xc9, 0x12, 0x82, 0x30, 0x14, 0x4, 0x87, 0x18, 0x50, 0x51, 0x44, 0x25, 0x42, 0x4, 0x77, 0xc4, 0x8d, 0x97, 0x0, 0xf9, 0xff, 0x8f, 0xb3, 0x88, 0xa4, 0x4a, 0xed, 0x63, 0x5f, 0xa6, 0x7, 0xf8, 0x7, 0x1e, 0xe3, 0x7e, 0x60, 0x19, 0x4f, 0x46, 0x1e, 0x0, 0x36, 0x8d, 0x4c, 0x67, 0x59, 0x65, 0x33, 0x6, 0x80, 0x47, 0xad, 0x56, 0x3d, 0xb7, 0x3c, 0x5d, 0x70, 0x0, 0xbe, 0xd1, 0x44, 0x65, 0x4d, 0x94, 0xc8, 0xc2, 0xf8, 0x0, 0x82, 0x4e, 0x91, 0x94, 0x15, 0x5d, 0xd2, 0xec, 0xde, 0x5, 0x83, 0x38, 0xc8, 0xe3, 0x63, 0x23, 0xce, 0xca, 0x9, 0x7a, 0x6e, 0xf3, 0x93, 0x48, 0x1a, 0x27, 0x14, 0x35, 0x3b, 0xb9, 0x5e, 0x56, 0xe4, 0x84, 0x22, 0xba, 0xa, 0x51, 0xd0, 0xb7, 0xa8, 0xcb, 0xfd, 0xcb, 0x9, 0x3b, 0xfb, 0x41, 0xdb, 0x59, 0x17, 0xa6, 0x94, 0x6e, 0xe3, 0x3e, 0x8c, 0x85, 0xf1, 0x90, 0x6e, 0xe6, 0x21, 0xfb, 0x39, 0xe7, 0x73, 0xe6, 0xfd, 0x5f, 0x7, 0xde, 0xc3, 0xb5, 0x16, 0x87, 0xb0, 0x9e, 0x42, 0x46, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; -static const unsigned char checker_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 -}; - static const unsigned char close_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp index de5da944bc..d1a958ad38 100644 --- a/scene/resources/height_map_shape_3d.cpp +++ b/scene/resources/height_map_shape_3d.cpp @@ -41,7 +41,7 @@ Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const { Vector2 size(map_width - 1, map_depth - 1); Vector2 start = size * -0.5; - const float *r = map_data.ptr(); + const real_t *r = map_data.ptr(); // reserve some memory for our points.. points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2) + ((map_width - 1) * (map_depth - 1) * 2)); @@ -105,7 +105,7 @@ void HeightMapShape3D::set_map_width(int p_new) { int new_size = map_width * map_depth; map_data.resize(map_width * map_depth); - float *w = map_data.ptrw(); + real_t *w = map_data.ptrw(); while (was_size < new_size) { w[was_size++] = 0.0; } @@ -129,7 +129,7 @@ void HeightMapShape3D::set_map_depth(int p_new) { int new_size = map_width * map_depth; map_data.resize(new_size); - float *w = map_data.ptrw(); + real_t *w = map_data.ptrw(); while (was_size < new_size) { w[was_size++] = 0.0; } @@ -143,7 +143,7 @@ int HeightMapShape3D::get_map_depth() const { return map_depth; } -void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) { +void HeightMapShape3D::set_map_data(Vector<real_t> p_new) { int size = (map_width * map_depth); if (p_new.size() != size) { // fail @@ -151,10 +151,10 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) { } // copy - float *w = map_data.ptrw(); - const float *r = p_new.ptr(); + real_t *w = map_data.ptrw(); + const real_t *r = p_new.ptr(); for (int i = 0; i < size; i++) { - float val = r[i]; + real_t val = r[i]; w[i] = val; if (i == 0) { min_height = val; @@ -174,7 +174,7 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) { notify_change_to_owners(); } -PackedFloat32Array HeightMapShape3D::get_map_data() const { +Vector<real_t> HeightMapShape3D::get_map_data() const { return map_data; } @@ -194,7 +194,7 @@ void HeightMapShape3D::_bind_methods() { HeightMapShape3D::HeightMapShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) { map_data.resize(map_width * map_depth); - float *w = map_data.ptrw(); + real_t *w = map_data.ptrw(); w[0] = 0.0; w[1] = 0.0; w[2] = 0.0; diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h index 1219791c56..1273aee040 100644 --- a/scene/resources/height_map_shape_3d.h +++ b/scene/resources/height_map_shape_3d.h @@ -38,7 +38,7 @@ class HeightMapShape3D : public Shape3D { int map_width = 2; int map_depth = 2; - PackedFloat32Array map_data; + Vector<real_t> map_data; real_t min_height = 0.0; real_t max_height = 0.0; @@ -51,8 +51,8 @@ public: int get_map_width() const; void set_map_depth(int p_new); int get_map_depth() const; - void set_map_data(PackedFloat32Array p_new); - PackedFloat32Array get_map_data() const; + void set_map_data(Vector<real_t> p_new); + Vector<real_t> get_map_data() const; virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 2f92872ad5..ad589a605e 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -653,6 +653,7 @@ enum OldArrayFormat { }; +#ifndef DISABLE_DEPRECATED static Array _convert_old_array(const Array &p_old) { Array new_array; new_array.resize(Mesh::ARRAY_MAX); @@ -677,6 +678,7 @@ static Mesh::PrimitiveType _old_primitives[7] = { Mesh::PRIMITIVE_TRIANGLE_STRIP, Mesh::PRIMITIVE_TRIANGLE_STRIP }; +#endif // DISABLE_DEPRECATED void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) { uint32_t dst_vertex_stride; diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index 3fb4f8f211..04b2437ae8 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -107,9 +107,9 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf bo = arrays[Mesh::ARRAY_BONES].operator Vector<int>().ptr(); } - const real_t *we = nullptr; + const float *we = nullptr; if (arrays[Mesh::ARRAY_WEIGHTS].get_type() != Variant::NIL) { - we = arrays[Mesh::ARRAY_WEIGHTS].operator Vector<real_t>().ptr(); + we = arrays[Mesh::ARRAY_WEIGHTS].operator Vector<float>().ptr(); } vertices.resize(vcount); diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index a08684a506..4dd3c874cb 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -417,9 +417,9 @@ void PolygonPathFinder::_set_data(const Dictionary &p_data) { } if (p_data.has("penalties")) { - Vector<float> penalties = p_data["penalties"]; + Vector<real_t> penalties = p_data["penalties"]; if (penalties.size() == pc) { - const float *pr2 = penalties.ptr(); + const real_t *pr2 = penalties.ptr(); for (int i = 0; i < pc; i++) { points.write[i].penalty = pr2[i]; } @@ -445,11 +445,11 @@ Dictionary PolygonPathFinder::_get_data() const { p.resize(MAX(0, points.size() - 2)); connections.resize(MAX(0, points.size() - 2)); ind.resize(edges.size() * 2); - Vector<float> penalties; + Vector<real_t> penalties; penalties.resize(MAX(0, points.size() - 2)); { Vector2 *wp = p.ptrw(); - float *pw = penalties.ptrw(); + real_t *pw = penalties.ptrw(); for (int i = 0; i < points.size() - 2; i++) { wp[i] = points[i].pos; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 2b93414906..dbe118a262 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -558,6 +558,12 @@ Error ResourceLoaderText::load() { resource_current++; + int_resources[id] = res; //always assign int resources + if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); + res->set_scene_unique_id(id); + } + while (true) { String assign; Variant value; @@ -585,12 +591,6 @@ Error ResourceLoaderText::load() { } } - int_resources[id] = res; //always assign int resources - if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { - res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); - res->set_scene_unique_id(id); - } - if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 424a54f344..44d524f142 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -76,8 +76,9 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const { if (default_textures.has(pi.name)) { //do not show default textures continue; } + String original_name = pi.name; pi.name = "shader_param/" + pi.name; - params_cache[pi.name] = pi.name; + params_cache[pi.name] = original_name; if (p_params) { //small little hack if (pi.type == Variant::RID) { diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp index e9adf67559..140c6f821f 100644 --- a/scene/resources/sprite_frames.cpp +++ b/scene/resources/sprite_frames.cpp @@ -122,14 +122,14 @@ Vector<String> SpriteFrames::get_animation_names() const { return names; } -void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) { +void SpriteFrames::set_animation_speed(const StringName &p_anim, double p_fps) { ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ")."); Map<StringName, Anim>::Element *E = animations.find(p_anim); ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); E->get().speed = p_fps; } -float SpriteFrames::get_animation_speed(const StringName &p_anim) const { +double SpriteFrames::get_animation_speed(const StringName &p_anim) const { const Map<StringName, Anim>::Element *E = animations.find(p_anim); ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); return E->get().speed; diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h index 282c5f20ab..fdfd6af5ab 100644 --- a/scene/resources/sprite_frames.h +++ b/scene/resources/sprite_frames.h @@ -37,7 +37,7 @@ class SpriteFrames : public Resource { GDCLASS(SpriteFrames, Resource); struct Anim { - float speed = 5.0; + double speed = 5.0; bool loop = true; Vector<Ref<Texture2D>> frames; }; @@ -64,8 +64,8 @@ public: void get_animation_list(List<StringName> *r_animations) const; Vector<String> get_animation_names() const; - void set_animation_speed(const StringName &p_anim, float p_fps); - float get_animation_speed(const StringName &p_anim) const; + void set_animation_speed(const StringName &p_anim, double p_fps); + double get_animation_speed(const StringName &p_anim) const; void set_animation_loop(const StringName &p_anim, bool p_loop); bool get_animation_loop(const StringName &p_anim) const; diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp index f1eff6e84f..5e60c7c4ed 100644 --- a/scene/resources/text_line.cpp +++ b/scene/resources/text_line.cpp @@ -56,8 +56,8 @@ void TextLine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::_set_bidi_override); ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL("")); - ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(VALIGN_CENTER)); + ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(INLINE_ALIGN_CENTER)); ClassDB::bind_method(D_METHOD("set_width", "width"), &TextLine::set_width); ClassDB::bind_method(D_METHOD("get_width"), &TextLine::get_width); @@ -175,13 +175,13 @@ bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_ return res; } -bool TextLine::add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { +bool TextLine::add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length); dirty = true; return res; } -bool TextLine::resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align) { +bool TextLine::resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { const_cast<TextLine *>(this)->_shape(); return TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align); } diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h index 1b5c1a3123..b773bd05be 100644 --- a/scene/resources/text_line.h +++ b/scene/resources/text_line.h @@ -76,8 +76,8 @@ public: bool get_preserve_control() const; bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); - bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1); - bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER); + bool add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1); + bool resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER); void set_align(HAlign p_align); HAlign get_align() const; diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index 958c94fe31..ffae551570 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -59,8 +59,8 @@ void TextParagraph::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap); ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL("")); - ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(VALIGN_CENTER)); + ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGN_CENTER)); ClassDB::bind_method(D_METHOD("set_align", "align"), &TextParagraph::set_align); ClassDB::bind_method(D_METHOD("get_align"), &TextParagraph::get_align); @@ -290,13 +290,13 @@ void TextParagraph::set_bidi_override(const Vector<Vector2i> &p_override) { dirty_lines = true; } -bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) { +bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length); dirty_lines = true; return res; } -bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align) { +bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align); dirty_lines = true; return res; diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index a34e745090..d0747a9e03 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -86,8 +86,8 @@ public: void clear_dropcap(); bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); - bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1); - bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER); + bool add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1); + bool resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER); void set_align(HAlign p_align); HAlign get_align() const; diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index a23152a6d1..a6815da6f4 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1648,19 +1648,10 @@ void VisualShader::_update_shader() const { { //fill render mode enums int idx = 0; - bool specular = false; while (render_mode_enums[idx].string) { if (shader_mode == render_mode_enums[idx].mode) { - if (shader_mode == Shader::MODE_SPATIAL) { - if (String(render_mode_enums[idx].string) == "specular") { - specular = true; - } - } - if (modes.has(render_mode_enums[idx].string) || specular) { - int which = 0; - if (modes.has(render_mode_enums[idx].string)) { - which = modes[render_mode_enums[idx].string]; - } + if (modes.has(render_mode_enums[idx].string)) { + int which = modes[render_mode_enums[idx].string]; int count = 0; for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode)).size(); i++) { String mode = ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader_mode))[i]; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index aec6932326..f3fa857682 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -48,27 +48,27 @@ void AudioStreamPlaybackResampled::_begin_resample() { void AudioStreamPlaybackResampled::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { float target_rate = AudioServer::get_singleton()->get_mix_rate(); - float global_rate_scale = AudioServer::get_singleton()->get_global_rate_scale(); + float playback_speed_scale = AudioServer::get_singleton()->get_playback_speed_scale(); - uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale) / double(target_rate * global_rate_scale)) * double(FP_LEN)); + uint64_t mix_increment = uint64_t(((get_stream_sampling_rate() * p_rate_scale * playback_speed_scale) / double(target_rate)) * double(FP_LEN)); for (int i = 0; i < p_frames; i++) { uint32_t idx = CUBIC_INTERP_HISTORY + uint32_t(mix_offset >> FP_BITS); - // 4 point, 4th order optimal resampling algorithm from: http://yehar.com/blog/wp-content/uploads/2009/08/deip.pdf + //standard cubic interpolation (great quality/performance ratio) + //this used to be moved to a LUT for greater performance, but nowadays CPU speed is generally faster than memory. float mu = (mix_offset & FP_MASK) / float(FP_LEN); AudioFrame y0 = internal_buffer[idx - 3]; AudioFrame y1 = internal_buffer[idx - 2]; AudioFrame y2 = internal_buffer[idx - 1]; AudioFrame y3 = internal_buffer[idx - 0]; - AudioFrame even1 = y2 + y1, odd1 = y2 - y1; - AudioFrame even2 = y3 + y0, odd2 = y3 - y0; - AudioFrame c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309; - AudioFrame c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288; - AudioFrame c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131; - AudioFrame c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800; - AudioFrame c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478; - p_buffer[i] = (((c4 * mu + c3) * mu + c2) * mu + c1) * mu + c0; + float mu2 = mu * mu; + AudioFrame a0 = 3 * y1 - 3 * y2 + y3 - y0; + AudioFrame a1 = 2 * y0 - 5 * y1 + 4 * y2 - y3; + AudioFrame a2 = y2 - y0; + AudioFrame a3 = 2 * y1; + + p_buffer[i] = (a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3) / 2; mix_offset += mix_increment; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 076cbb58af..4c54188cb2 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -913,14 +913,14 @@ bool AudioServer::is_bus_channel_active(int p_bus, int p_channel) const { return buses[p_bus]->channels[p_channel].active; } -void AudioServer::set_global_rate_scale(float p_scale) { +void AudioServer::set_playback_speed_scale(float p_scale) { ERR_FAIL_COND(p_scale <= 0); - global_rate_scale = p_scale; + playback_speed_scale = p_scale; } -float AudioServer::get_global_rate_scale() const { - return global_rate_scale; +float AudioServer::get_playback_speed_scale() const { + return playback_speed_scale; } void AudioServer::init_channels_and_buffers() { @@ -1277,8 +1277,8 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bus_peak_volume_left_db", "bus_idx", "channel"), &AudioServer::get_bus_peak_volume_left_db); ClassDB::bind_method(D_METHOD("get_bus_peak_volume_right_db", "bus_idx", "channel"), &AudioServer::get_bus_peak_volume_right_db); - ClassDB::bind_method(D_METHOD("set_global_rate_scale", "scale"), &AudioServer::set_global_rate_scale); - ClassDB::bind_method(D_METHOD("get_global_rate_scale"), &AudioServer::get_global_rate_scale); + ClassDB::bind_method(D_METHOD("set_playback_speed_scale", "scale"), &AudioServer::set_playback_speed_scale); + ClassDB::bind_method(D_METHOD("get_playback_speed_scale"), &AudioServer::get_playback_speed_scale); ClassDB::bind_method(D_METHOD("lock"), &AudioServer::lock); ClassDB::bind_method(D_METHOD("unlock"), &AudioServer::unlock); @@ -1302,7 +1302,7 @@ void AudioServer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "bus_count"), "set_bus_count", "get_bus_count"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "device"), "set_device", "get_device"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rate_scale"), "set_global_rate_scale", "get_global_rate_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed_scale"), "set_playback_speed_scale", "get_playback_speed_scale"); ADD_SIGNAL(MethodInfo("bus_layout_changed")); @@ -1322,7 +1322,7 @@ AudioServer::AudioServer() { #endif mix_time = 0; mix_size = 0; - global_rate_scale = 1; + playback_speed_scale = 1; } AudioServer::~AudioServer() { diff --git a/servers/audio_server.h b/servers/audio_server.h index a1a373e1ca..7974c4a2ad 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -177,7 +177,7 @@ private: int channel_count; int to_mix; - float global_rate_scale; + float playback_speed_scale; struct Bus { StringName name; @@ -316,8 +316,8 @@ public: bool is_bus_channel_active(int p_bus, int p_channel) const; - void set_global_rate_scale(float p_scale); - float get_global_rate_scale() const; + void set_playback_speed_scale(float p_scale); + float get_playback_speed_scale() const; virtual void init(); virtual void finish(); diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index b4a95651cb..74bef433dc 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -266,6 +266,10 @@ public: void integrate_forces(real_t p_step); void integrate_velocities(real_t p_step); + _FORCE_INLINE_ Vector2 get_velocity_in_local_point(const Vector2 &rel_pos) const { + return linear_velocity + Vector2(-angular_velocity * rel_pos.y, angular_velocity * rel_pos.x); + } + _FORCE_INLINE_ Vector2 get_motion() const { if (mode > PhysicsServer2D::BODY_MODE_KINEMATIC) { return new_transform.get_origin() - get_transform().get_origin(); @@ -352,6 +356,8 @@ public: virtual void set_transform(const Transform2D &p_transform) override { body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform); } virtual Transform2D get_transform() const override { return body->get_transform(); } + virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const override { return body->get_velocity_in_local_point(p_position); } + virtual void add_central_force(const Vector2 &p_force) override { body->add_central_force(p_force); } virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) override { body->add_force(p_force, p_position); } virtual void add_torque(real_t p_torque) override { body->add_torque(p_torque); } diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index 0fa31c5037..bdc615ab6c 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -389,6 +389,8 @@ public: virtual void set_transform(const Transform3D &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); } virtual Transform3D get_transform() const override { return body->get_transform(); } + virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const override { return body->get_velocity_in_local_point(p_position); } + virtual void add_central_force(const Vector3 &p_force) override { body->add_central_force(p_force); } virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override { body->add_force(p_force, p_position); diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp index 6a7f2b73c5..852e9ecd74 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/collision_solver_3d_sat.cpp @@ -956,9 +956,12 @@ static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transfo const Vector3 *vertices = mesh.vertices.ptr(); int vertex_count = mesh.vertices.size(); + // Precalculating this makes the transforms faster. + Basis b_xform_normal = p_transform_b.basis.inverse().transposed(); + // faces of B for (int i = 0; i < face_count; i++) { - Vector3 axis = p_transform_b.xform(faces[i].plane).normal; + Vector3 axis = b_xform_normal.xform(faces[i].plane.normal).normalized(); if (!separator.test_axis(axis)) { return; @@ -1379,9 +1382,12 @@ static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform3 } } + // Precalculating this makes the transforms faster. + Basis b_xform_normal = p_transform_b.basis.inverse().transposed(); + // faces of B for (int i = 0; i < face_count; i++) { - Vector3 axis = p_transform_b.xform(faces[i].plane).normal; + Vector3 axis = b_xform_normal.xform(faces[i].plane.normal).normalized(); if (!separator.test_axis(axis)) { return; @@ -1733,9 +1739,12 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf int edge_count = mesh.edges.size(); const Vector3 *vertices = mesh.vertices.ptr(); + // Precalculating this makes the transforms faster. + Basis b_xform_normal = p_transform_b.basis.inverse().transposed(); + // faces of B for (int i = 0; i < face_count; i++) { - Vector3 axis = p_transform_b.xform(faces[i].plane).normal; + Vector3 axis = b_xform_normal.xform(faces[i].plane.normal).normalized(); if (!separator.test_axis(axis)) { return; @@ -2057,20 +2066,24 @@ static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const const Vector3 *vertices_B = mesh_B.vertices.ptr(); int vertex_count_B = mesh_B.vertices.size(); + // Precalculating this makes the transforms faster. + Basis a_xform_normal = p_transform_b.basis.inverse().transposed(); + // faces of A for (int i = 0; i < face_count_A; i++) { - Vector3 axis = p_transform_a.xform(faces_A[i].plane).normal; - //Vector3 axis = p_transform_a.basis.xform( faces_A[i].plane.normal ).normalized(); + Vector3 axis = a_xform_normal.xform(faces_A[i].plane.normal).normalized(); if (!separator.test_axis(axis)) { return; } } + // Precalculating this makes the transforms faster. + Basis b_xform_normal = p_transform_b.basis.inverse().transposed(); + // faces of B for (int i = 0; i < face_count_B; i++) { - Vector3 axis = p_transform_b.xform(faces_B[i].plane).normal; - //Vector3 axis = p_transform_b.basis.xform( faces_B[i].plane.normal ).normalized(); + Vector3 axis = b_xform_normal.xform(faces_B[i].plane.normal).normalized(); if (!separator.test_axis(axis)) { return; diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index c1a9d6259d..e2ab84428b 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -854,7 +854,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) { body->set_ray_pickable(p_enable); } -bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -862,7 +862,7 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, _update_shapes(); - return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude); } int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index 0ccd15fbb2..326b6fbe7a 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -242,7 +242,7 @@ public: virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; - virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override; virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; // this function only works on physics process, errors and returns null otherwise diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h index 9beec22bcd..c3c2e50e56 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.h +++ b/servers/physics_3d/physics_server_3d_wrap_mt.h @@ -250,9 +250,9 @@ public: FUNC2(body_set_ray_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { + bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); - return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); + return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude); } int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override { diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index 04a174f9c8..5b3721861e 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -1635,7 +1635,7 @@ ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() { /* HEIGHT MAP SHAPE */ -Vector<float> HeightMapShape3DSW::get_heights() const { +Vector<real_t> HeightMapShape3DSW::get_heights() const { return heights; } @@ -1932,7 +1932,7 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -void HeightMapShape3DSW::_setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { +void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { heights = p_heights; width = p_width; depth = p_depth; @@ -1966,8 +1966,12 @@ void HeightMapShape3DSW::set_data(const Variant &p_data) { ERR_FAIL_COND(depth <= 0.0); Variant heights_variant = d["heights"]; - Vector<float> heights_buffer; + Vector<real_t> heights_buffer; +#ifdef REAL_T_IS_DOUBLE + if (heights_variant.get_type() == Variant::PACKED_FLOAT64_ARRAY) { +#else if (heights_variant.get_type() == Variant::PACKED_FLOAT32_ARRAY) { +#endif // Ready-to-use heights can be passed. heights_buffer = heights_variant; } else if (heights_variant.get_type() == Variant::OBJECT) { @@ -1980,13 +1984,17 @@ void HeightMapShape3DSW::set_data(const Variant &p_data) { PackedByteArray im_data = image->get_data(); heights_buffer.resize(image->get_width() * image->get_height()); - float *w = heights_buffer.ptrw(); - float *rp = (float *)im_data.ptr(); + real_t *w = heights_buffer.ptrw(); + real_t *rp = (real_t *)im_data.ptr(); for (int i = 0; i < heights_buffer.size(); ++i) { w[i] = rp[i]; } } else { +#ifdef REAL_T_IS_DOUBLE + ERR_FAIL_MSG("Expected PackedFloat64Array or float Image."); +#else ERR_FAIL_MSG("Expected PackedFloat32Array or float Image."); +#endif } // Compute min and max heights or use precomputed values. diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index 0d1b7cc3d7..72be34b788 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -389,12 +389,12 @@ public: }; struct HeightMapShape3DSW : public ConcaveShape3DSW { - Vector<float> heights; + Vector<real_t> heights; int width = 0; int depth = 0; Vector3 local_origin; - _FORCE_INLINE_ float _get_height(int p_x, int p_z) const { + _FORCE_INLINE_ real_t _get_height(int p_x, int p_z) const { return heights[(p_z * width) + p_x]; } @@ -406,10 +406,10 @@ struct HeightMapShape3DSW : public ConcaveShape3DSW { void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const; - void _setup(const Vector<float> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); + void _setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); public: - Vector<float> get_heights() const; + Vector<real_t> get_heights() const; int get_width() const; int get_depth() const; diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index 1037243d3b..2a39a9d363 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -720,7 +720,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_t return rays_found; } -bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) { //give me back regular physics engine logic //this is madness //and most people using this function will think @@ -801,6 +801,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co for (int i = 0; i < amount; i++) { const CollisionObject3DSW *col_obj = intersection_query_results[i]; + if (p_exclude.has(col_obj->get_self())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) { @@ -890,6 +893,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co for (int i = 0; i < amount; i++) { const CollisionObject3DSW *col_obj = intersection_query_results[i]; + if (p_exclude.has(col_obj->get_self())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) { @@ -1015,6 +1021,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co for (int i = 0; i < amount; i++) { const CollisionObject3DSW *col_obj = intersection_query_results[i]; + if (p_exclude.has(col_obj->get_self())) { + continue; + } int shape_idx = intersection_query_subindex_results[i]; if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) { diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h index 18e93c90cc..580693deba 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/space_3d_sw.h @@ -204,7 +204,7 @@ public: uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } int test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); - bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); + bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>()); Space3DSW(); ~Space3DSW(); diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index e8272f377e..2e44a1a10b 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -89,6 +89,8 @@ void PhysicsDirectBodyState2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState2D::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState2D::get_transform); + ClassDB::bind_method(D_METHOD("get_velocity_at_local_position", "local_position"), &PhysicsDirectBodyState2D::get_velocity_at_local_position); + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState2D::add_central_force); ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState2D::add_force, Vector2()); ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState2D::add_torque); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 8542b54838..fafde62599 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -60,6 +60,8 @@ public: virtual void set_transform(const Transform2D &p_transform) = 0; virtual Transform2D get_transform() const = 0; + virtual Vector2 get_velocity_at_local_position(const Vector2 &p_position) const = 0; + virtual void add_central_force(const Vector2 &p_force) = 0; virtual void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) = 0; virtual void add_torque(real_t p_torque) = 0; diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 3ed8841119..b4ee5fbaf0 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -91,6 +91,8 @@ void PhysicsDirectBodyState3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsDirectBodyState3D::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsDirectBodyState3D::get_transform); + ClassDB::bind_method(D_METHOD("get_velocity_at_local_position", "local_position"), &PhysicsDirectBodyState3D::get_velocity_at_local_position); + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState3D::add_central_force, Vector3()); ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState3D::add_force, Vector3()); ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState3D::add_torque); @@ -445,12 +447,16 @@ void PhysicsTestMotionResult3D::_bind_methods() { /////////////////////////////////////// -bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result) { +bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result, bool p_exclude_raycast_shapes, const Vector<RID> &p_exclude) { MotionResult *r = nullptr; if (p_result.is_valid()) { r = p_result->get_result_ptr(); } - return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r); + Set<RID> exclude; + for (int i = 0; i < p_exclude.size(); i++) { + exclude.insert(p_exclude[i]); + } + return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes, exclude); } RID PhysicsServer3D::shape_create(ShapeType p_shape) { @@ -606,7 +612,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable); - ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result", "exclude_raycast_shapes", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Array())); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 17bae9a057..0d3d5bd4a1 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -62,6 +62,8 @@ public: virtual void set_transform(const Transform3D &p_transform) = 0; virtual Transform3D get_transform() const = 0; + virtual Vector3 get_velocity_at_local_position(const Vector3 &p_position) const = 0; + virtual void add_central_force(const Vector3 &p_force) = 0; virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) = 0; virtual void add_torque(const Vector3 &p_torque) = 0; @@ -210,7 +212,7 @@ class PhysicsServer3D : public Object { static PhysicsServer3D *singleton; - virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>()); + virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), bool p_exclude_raycast_shapes = true, const Vector<RID> &p_exclude = Vector<RID>()); protected: static void _bind_methods(); @@ -489,7 +491,7 @@ public: Variant collider_metadata; }; - virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) = 0; struct SeparationResult { real_t collision_depth; diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index b7cf0983af..b2fffca3ea 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -540,13 +540,13 @@ public: void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {} void particles_set_emitting(RID p_particles, bool p_emitting) override {} void particles_set_amount(RID p_particles, int p_amount) override {} - void particles_set_lifetime(RID p_particles, float p_lifetime) override {} + void particles_set_lifetime(RID p_particles, double p_lifetime) override {} void particles_set_one_shot(RID p_particles, bool p_one_shot) override {} - void particles_set_pre_process_time(RID p_particles, float p_time) override {} + void particles_set_pre_process_time(RID p_particles, double p_time) override {} void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) override {} void particles_set_randomness_ratio(RID p_particles, float p_ratio) override {} void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override {} - void particles_set_speed_scale(RID p_particles, float p_scale) override {} + void particles_set_speed_scale(RID p_particles, double p_scale) override {} void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {} void particles_set_process_material(RID p_particles, RID p_material) override {} void particles_set_fixed_fps(RID p_particles, int p_fps) override {} @@ -724,7 +724,7 @@ public: class RasterizerDummy : public RendererCompositor { private: uint64_t frame = 1; - float delta = 0; + double delta = 0; protected: RasterizerCanvasDummy canvas; @@ -765,7 +765,7 @@ public: bool is_low_end() const override { return true; } uint64_t get_frame_number() const override { return frame; } - float get_frame_delta_time() const override { return delta; } + double get_frame_delta_time() const override { return delta; } RasterizerDummy() {} ~RasterizerDummy() {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index ec0a8347f8..fd7d5b91fa 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -639,17 +639,19 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point j2 = j + 1; - Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; + Vector2 dir = (t + prev_t).normalized(); + Vector2 tangent = dir * p_width * 0.5; + Vector2 border = dir * 2.0; Vector2 pos = p_points[i]; points_ptr[j] = pos + tangent; points_ptr[j2] = pos - tangent; - points_top_ptr[j] = pos + tangent + tangent; + points_top_ptr[j] = pos + tangent + border; points_top_ptr[j2] = pos + tangent; points_bottom_ptr[j] = pos - tangent; - points_bottom_ptr[j2] = pos - tangent - tangent; + points_bottom_ptr[j2] = pos - tangent - border; if (i < p_colors.size()) { color = p_colors[i]; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 5fe9cdffba..6206849b66 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -85,7 +85,7 @@ public: virtual void end_frame(bool p_swap_buffers) = 0; virtual void finalize() = 0; virtual uint64_t get_frame_number() const = 0; - virtual float get_frame_delta_time() const = 0; + virtual double get_frame_delta_time() const = 0; virtual bool is_low_end() const = 0; virtual bool is_xr_enabled() const; diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 699f4a4b90..c609f25e31 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -70,6 +70,28 @@ RID EffectsRD::_get_uniform_set_from_image(RID p_image) { return uniform_set; } +RID EffectsRD::_get_uniform_set_for_input(RID p_texture) { + if (input_to_uniform_set_cache.has(p_texture)) { + RID uniform_set = input_to_uniform_set_cache[p_texture]; + if (RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + return uniform_set; + } + } + + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_INPUT_ATTACHMENT; + u.binding = 0; + u.ids.push_back(p_texture); + uniforms.push_back(u); + // This is specific to our subpass shader + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, TONEMAP_MODE_SUBPASS), 0); + + input_to_uniform_set_cache[p_texture] = uniform_set; + + return uniform_set; +} + RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) { if (texture_to_uniform_set_cache.has(p_texture)) { RID uniform_set = texture_to_uniform_set_cache[p_texture]; @@ -85,7 +107,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) u.ids.push_back(p_use_mipmaps ? default_mipmap_sampler : default_sampler); u.ids.push_back(p_texture); uniforms.push_back(u); - //anything with the same configuration (one texture in binding 0 for set 0), is good + // anything with the same configuration (one texture in binding 0 for set 0), is good RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, tonemap.shader.version_get_shader(tonemap.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; @@ -778,11 +800,11 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone if (p_settings.view_count > 1) { // Use MULTIVIEW versions - mode += 4; + mode += 6; } RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer), false, RD::get_singleton()->draw_list_get_current_pass())); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); @@ -794,6 +816,45 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone RD::get_singleton()->draw_list_end(); } +void EffectsRD::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings) { + memset(&tonemap.push_constant, 0, sizeof(TonemapPushConstant)); + + tonemap.push_constant.use_bcs = p_settings.use_bcs; + tonemap.push_constant.bcs[0] = p_settings.brightness; + tonemap.push_constant.bcs[1] = p_settings.contrast; + tonemap.push_constant.bcs[2] = p_settings.saturation; + + ERR_FAIL_COND_MSG(p_settings.use_glow, "Glow is not supported when using subpasses."); + tonemap.push_constant.use_glow = p_settings.use_glow; + + int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; + if (p_settings.view_count > 1) { + // Use MULTIVIEW versions + mode += 6; + } + + tonemap.push_constant.tonemapper = p_settings.tonemap_mode; + tonemap.push_constant.use_auto_exposure = p_settings.use_auto_exposure; + tonemap.push_constant.exposure = p_settings.exposure; + tonemap.push_constant.white = p_settings.white; + tonemap.push_constant.auto_exposure_grey = p_settings.auto_exposure_grey; + + tonemap.push_constant.use_color_correction = p_settings.use_color_correction; + + tonemap.push_constant.use_debanding = p_settings.use_debanding; + + RD::get_singleton()->draw_list_bind_render_pipeline(p_subpass_draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, p_dst_format_id, false, RD::get_singleton()->draw_list_get_current_pass())); + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_for_input(p_source_color), 0); + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.exposure_texture), 1); // should be set to a default texture, it's ignored + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.glow_texture, true), 2); // should be set to a default texture, it's ignored + RD::get_singleton()->draw_list_bind_uniform_set(p_subpass_draw_list, _get_uniform_set_from_texture(p_settings.color_correction_texture), 3); + + RD::get_singleton()->draw_list_bind_index_array(p_subpass_draw_list, index_array); + + RD::get_singleton()->draw_list_set_push_constant(p_subpass_draw_list, &tonemap.push_constant, sizeof(TonemapPushConstant)); + RD::get_singleton()->draw_list_draw(p_subpass_draw_list, true); +} + void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer."); @@ -1813,12 +1874,16 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n"); tonemap_modes.push_back("\n#define USE_1D_LUT\n"); tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define SUBPASS\n"); + tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n"); // multiview versions of our shaders tonemap_modes.push_back("\n#define MULTIVIEW\n"); tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n"); tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n"); tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n"); tonemap.shader.initialize(tonemap_modes); @@ -1827,6 +1892,8 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false); tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false); tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, false); } tonemap.shader_version = tonemap.shader.version_create(); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index eff891571a..79d9a8b738 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -238,11 +238,15 @@ private: TONEMAP_MODE_BICUBIC_GLOW_FILTER, TONEMAP_MODE_1D_LUT, TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT, + TONEMAP_MODE_SUBPASS, + TONEMAP_MODE_SUBPASS_1D_LUT, TONEMAP_MODE_NORMAL_MULTIVIEW, TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, TONEMAP_MODE_1D_LUT_MULTIVIEW, TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, + TONEMAP_MODE_SUBPASS_MULTIVIEW, + TONEMAP_MODE_SUBPASS_1D_LUT_MULTIVIEW, TONEMAP_MODE_MAX }; @@ -718,6 +722,7 @@ private: RID index_array; Map<RID, RID> texture_to_uniform_set_cache; + Map<RID, RID> input_to_uniform_set_cache; Map<RID, RID> image_to_uniform_set_cache; @@ -751,6 +756,7 @@ private: Map<TextureSamplerPair, RID> texture_sampler_to_compute_uniform_set_cache; RID _get_uniform_set_from_image(RID p_texture); + RID _get_uniform_set_for_input(RID p_texture); RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false); RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler); @@ -842,6 +848,7 @@ public: }; void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); + void tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_color, RD::FramebufferFormatID p_dst_format_id, const TonemapSettings &p_settings); void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set); void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index ac20515c28..0d304556c2 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -183,7 +183,7 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { } } -void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) { +void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) { clear(); ERR_FAIL_COND_MSG(p_view_count != 1, "Multiple views is currently not supported in this renderer, please use the mobile renderer for VR support"); @@ -483,8 +483,8 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p } if (material_uniform_set != prev_material_uniform_set) { - //update uniform set - if (material_uniform_set.is_valid()) { + // Update uniform set. + if (RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); } @@ -1555,6 +1555,14 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } RD::get_singleton()->draw_command_end_label(); + + if (p_render_data->render_buffers.is_valid()) { + _debug_draw_cluster(p_render_data->render_buffers); + + RENDER_TIMESTAMP("Tonemap"); + + _render_buffers_post_process_and_tonemap(p_render_data); + } } void RenderForwardClustered::_render_shadow_begin() { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 6682c5e9b0..676f633d33 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -112,7 +112,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { void ensure_specular(); void ensure_voxelgi(); void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count); ~RenderBufferDataForwardClustered(); }; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 4725599148..dea2975660 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -78,12 +78,16 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() { color = RID(); depth = RID(); - color_fb = RID(); + for (int i = 0; i < FB_CONFIG_MAX; i++) { + color_fbs[i] = RID(); + } } -void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) { +void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) { clear(); + bool is_half_resolution = false; // Set this once we support this feature. + msaa = p_msaa; width = p_width; @@ -93,15 +97,50 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b color = p_color_buffer; depth = p_depth_buffer; - RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format(); + // We are creating 4 configurations here for our framebuffers. if (p_msaa == RS::VIEWPORT_MSAA_DISABLED) { Vector<RID> fb; - fb.push_back(p_color_buffer); - fb.push_back(depth); + fb.push_back(p_color_buffer); // 0 - color buffer + fb.push_back(depth); // 1 - depth buffer + + // Now define our subpasses + Vector<RD::FramebufferPass> passes; + RD::FramebufferPass pass; + + // re-using the same attachments + pass.color_attachments.push_back(0); + pass.depth_attachment = 1; + + // - opaque pass + passes.push_back(pass); + color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); + + // - add sky pass + passes.push_back(pass); + color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); + + // - add alpha pass + passes.push_back(pass); + color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); - color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count); + if (!is_half_resolution) { + // - add blit to 2D pass + fb.push_back(p_target_buffer); // 2 - target buffer + + RD::FramebufferPass blit_pass; + blit_pass.color_attachments.push_back(2); + blit_pass.input_attachments.push_back(0); + passes.push_back(blit_pass); + + color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); + } else { + // can't do our blit pass if resolutions don't match + color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID(); + } } else { + RD::DataFormat color_format = RenderForwardMobile::singleton->_render_buffers_get_color_format(); + RD::TextureFormat tf; if (view_count > 1) { tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; @@ -134,14 +173,87 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b { Vector<RID> fb; - fb.push_back(color_msaa); - fb.push_back(depth_msaa); + fb.push_back(color_msaa); // 0 - msaa color buffer + fb.push_back(depth_msaa); // 1 - msaa depth buffer + + // Now define our subpasses + Vector<RD::FramebufferPass> passes; + RD::FramebufferPass pass; + + // re-using the same attachments + pass.color_attachments.push_back(0); + pass.depth_attachment = 1; + + // - opaque pass + passes.push_back(pass); + + // - add sky pass + fb.push_back(color); // 2 - color buffer + passes.push_back(pass); // without resolve for our 3 + 4 subpass config + { + // but with resolve for our 2 subpass config + Vector<RD::FramebufferPass> two_passes; + two_passes.push_back(pass); // opaque subpass without resolve + pass.resolve_attachments.push_back(2); + two_passes.push_back(pass); // sky subpass with resolve + + color_fbs[FB_CONFIG_TWO_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, two_passes, RenderingDevice::INVALID_ID, view_count); + } + + // - add alpha pass (with resolve, we just added that above) + passes.push_back(pass); + color_fbs[FB_CONFIG_THREE_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); - color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count); + { + // we also need our one pass with resolve + Vector<RD::FramebufferPass> one_pass_with_resolve; + one_pass_with_resolve.push_back(pass); // note our pass configuration already has resolve.. + color_fbs[FB_CONFIG_ONE_PASS] = RD::get_singleton()->framebuffer_create_multipass(fb, one_pass_with_resolve, RenderingDevice::INVALID_ID, view_count); + } + + if (!is_half_resolution) { + // - add blit to 2D pass + fb.push_back(p_target_buffer); // 3 - target buffer + RD::FramebufferPass blit_pass; + blit_pass.color_attachments.push_back(3); + blit_pass.input_attachments.push_back(2); + passes.push_back(blit_pass); + + color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RD::get_singleton()->framebuffer_create_multipass(fb, passes, RenderingDevice::INVALID_ID, view_count); + } else { + // can't do our blit pass if resolutions don't match + color_fbs[FB_CONFIG_FOUR_SUBPASSES] = RID(); + } } } } +RID RenderForwardMobile::reflection_probe_create_framebuffer(RID p_color, RID p_depth) { + // Our attachments + Vector<RID> fb; + fb.push_back(p_color); // 0 + fb.push_back(p_depth); // 1 + + // Now define our subpasses + Vector<RD::FramebufferPass> passes; + RD::FramebufferPass pass; + + // re-using the same attachments + pass.color_attachments.push_back(0); + pass.depth_attachment = 1; + + // - opaque pass + passes.push_back(pass); + + // - sky pass + passes.push_back(pass); + + // - alpha pass + passes.push_back(pass); + + return RD::get_singleton()->framebuffer_create_multipass(fb, passes); +} + RenderForwardMobile::RenderBufferDataForwardMobile::~RenderBufferDataForwardMobile() { clear(); } @@ -365,14 +477,29 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color scene_state.ubo.viewport_size[1] = vp_he.y; scene_state.ubo.directional_light_count = 0; + // We can only use our full subpass approach if we're: + // - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE + // - not using ssr/sss (currently not supported) + // - not using glow or other post effects (can't do 4th subpass) + // - rendering to a half sized render buffer (can't do 4th subpass) + // We'll need to restrict how far we're going with subpasses based on this. + Size2i screen_size; - RID opaque_framebuffer; - RID alpha_framebuffer; + RID framebuffer; bool reverse_cull = false; + bool using_subpass_transparent = true; + bool using_subpass_post_process = true; - // I don't think we support either of these in our mobile renderer so probably should phase them out - bool using_ssr = false; - bool using_sss = false; + bool is_half_resolution = false; // Set this once we support this feature. + bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out + bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out + + // fill our render lists early so we can find out if we use various features + _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); + render_list[RENDER_LIST_OPAQUE].sort_by_key(); + render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority(); + _fill_element_info(RENDER_LIST_OPAQUE); + _fill_element_info(RENDER_LIST_ALPHA); if (p_render_data->render_info) { p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size(); @@ -384,15 +511,36 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color screen_size.x = render_buffer->width; screen_size.y = render_buffer->height; - opaque_framebuffer = render_buffer->color_fb; - alpha_framebuffer = opaque_framebuffer; + if (is_half_resolution) { + // can't do blit subpass + using_subpass_post_process = false; + } else if (env && (env->glow_enabled || env->auto_exposure || camera_effects_uses_dof(p_render_data->camera_effects))) { + // can't do blit subpass + using_subpass_post_process = false; + } + + if (scene_state.used_screen_texture || scene_state.used_depth_texture) { + // can't use our last two subpasses + using_subpass_transparent = false; + using_subpass_post_process = false; + } + + if (using_subpass_post_process) { + // all as subpasses + framebuffer = render_buffer->color_fbs[FB_CONFIG_FOUR_SUBPASSES]; + } else if (using_subpass_transparent) { + // our tonemap pass is separate + framebuffer = render_buffer->color_fbs[FB_CONFIG_THREE_SUBPASSES]; + } else { + // only opaque and sky as subpasses + framebuffer = render_buffer->color_fbs[FB_CONFIG_TWO_SUBPASSES]; + } } else if (p_render_data->reflection_probe.is_valid()) { uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe); screen_size.x = resolution; screen_size.y = resolution; - opaque_framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); - alpha_framebuffer = opaque_framebuffer; + framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass); if (storage->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) { p_render_data->environment = RID(); //no environment on interiors @@ -400,6 +548,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } reverse_cull = true; + using_subpass_transparent = true; // we ignore our screen/depth texture here + using_subpass_post_process = false; // not applicable at all for reflection probes. } else { ERR_FAIL(); //bug? } @@ -411,17 +561,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) - _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); - render_list[RENDER_LIST_OPAQUE].sort_by_key(); - render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority(); - - // we no longer use this... - _fill_instance_data(RENDER_LIST_OPAQUE); - _fill_instance_data(RENDER_LIST_ALPHA); - - RD::get_singleton()->draw_command_end_label(); - - // note, no depth prepass here! + RD::get_singleton()->draw_command_end_label(); // Render Setup // setup environment RID radiance_texture; @@ -496,97 +636,199 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color // do not try to draw sky if invalid draw_sky = false; } - RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_command_end_label(); // Setup Sky } } else { clear_color = p_default_bg_color; } - // opaque pass + // update sky buffers (if required) + if (draw_sky || draw_sky_fog_only) { + // !BAS! @TODO See if we can limit doing some things double and maybe even move this into _pre_opaque_render + // and change Forward Clustered in the same way as we have here (but without using subpasses) + RENDER_TIMESTAMP("Setup Sky resolution buffers"); + + RD::get_singleton()->draw_command_begin_label("Setup Sky resolution buffers"); + + if (p_render_data->reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + CameraMatrix projection = correction * p_render_data->cam_projection; + sky.update_res_buffers(env, 1, &projection, p_render_data->cam_transform, time); + } else { + sky.update_res_buffers(env, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time); + } + + RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers + } - // !BAS! Look into this, seems most of the code in here related to clustered only, may want to move this code into ForwardClustered/RenderForwardMobile before calling it from here - // does trigger shadow map rendering so kinda important _pre_opaque_render(p_render_data, false, false, RID(), RID()); - RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); + { + if (render_buffer) { + RD::get_singleton()->draw_command_begin_label("Render 3D Pass"); + } else { + RD::get_singleton()->draw_command_begin_label("Render Reflection Probe Pass"); + } - scene_state.ubo.directional_light_count = p_render_data->directional_light_count; + // opaque pass - _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid()); + RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass"); - RENDER_TIMESTAMP("Render Opaque Pass"); + scene_state.ubo.directional_light_count = p_render_data->directional_light_count; - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true); + _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid()); - bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; - bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; + RENDER_TIMESTAMP("Render Opaque Subpass"); - { - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); + RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true); - // regular forward for now - Vector<Color> c; - c.push_back(clear_color.to_linear()); + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; + bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); - _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); - } + { + bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); + bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); + + // regular forward for now + Vector<Color> c; + c.push_back(clear_color.to_linear()); // our render buffer + if (render_buffer) { + if (render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { + c.push_back(clear_color.to_linear()); // our resolve buffer + } + if (using_subpass_post_process) { + c.push_back(Color()); // our 2D buffer we're copying into + } + } - RD::get_singleton()->draw_command_end_label(); + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); + render_list_params.framebuffer_format = fb_format; + if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { + // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); + _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); + } + } - if (draw_sky || draw_sky_fog_only) { - RENDER_TIMESTAMP("Render Sky"); + RD::get_singleton()->draw_command_end_label(); //Render Opaque Subpass - RD::get_singleton()->draw_command_begin_label("Draw Sky"); + if (draw_sky || draw_sky_fog_only) { + RENDER_TIMESTAMP("Render Sky Subpass"); - if (p_render_data->reflection_probe.is_valid()) { - CameraMatrix correction; - correction.set_depth_correction(true); - CameraMatrix projection = correction * p_render_data->cam_projection; - sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time); + RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass"); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass(); + + if (p_render_data->reflection_probe.is_valid()) { + CameraMatrix correction; + correction.set_depth_correction(true); + CameraMatrix projection = correction * p_render_data->cam_projection; + sky.draw(draw_list, env, framebuffer, 1, &projection, p_render_data->cam_transform, time); + } else { + sky.draw(draw_list, env, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time); + } + + RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass + + // note, if MSAA is used in 2-subpass approach we should get an automatic resolve here } else { - sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time); + // switch to subpass but we do nothing here so basically we skip (though this should trigger resolve with 2-subpass MSAA). + RD::get_singleton()->draw_list_switch_to_next_pass(); } - RD::get_singleton()->draw_command_end_label(); - } - if (render_buffer && !can_continue_color && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); - /* - if (using_separate_specular) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular); + if (!using_subpass_transparent) { + // We're done with our subpasses so end our container pass + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + + RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass } - */ - } - if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); - } + // transparent pass + RENDER_TIMESTAMP("Render Transparent Subpass"); - // transparent pass - RENDER_TIMESTAMP("Render Transparent Pass"); + RD::get_singleton()->draw_command_begin_label("Render Transparent Subpass"); - RD::get_singleton()->draw_command_begin_label("Render Transparent Pass"); + rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true); - rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_ALPHA, p_render_data, radiance_texture, true); + if (using_subpass_transparent) { + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); + render_list_params.framebuffer_format = fb_format; + if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { + // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_switch_to_next_pass_split(thread_draw_lists.size(), thread_draw_lists.ptr()); + render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass(); + render_list_params.subpass = RD::get_singleton()->draw_list_get_current_pass(); + _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); + } - _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); + RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass - { - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); - _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + // note if we are using MSAA we should get an automatic resolve through our subpass configuration. + + // blit to tonemap + if (render_buffer && using_subpass_post_process) { + _post_process_subpass(render_buffer->color, framebuffer, p_render_data); + } + + RD::get_singleton()->draw_command_end_label(); // Render 3D Pass / Render Reflection Probe Pass + + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + } else { + framebuffer = render_buffer->color_fbs[FB_CONFIG_ONE_PASS]; + + // this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation + // _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); + + RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); + render_list_params.framebuffer_format = fb_format; + if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { + // secondary command buffers need more testing at this time + //multi threaded + thread_draw_lists.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + RD::get_singleton()->draw_list_begin_split(framebuffer, thread_draw_lists.size(), thread_draw_lists.ptr(), can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + RendererThreadPool::singleton->thread_work_pool.do_work(thread_draw_lists.size(), this, &RenderForwardMobile::_render_list_thread_function, &render_list_params); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + } else { + //single threaded + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + _render_list(draw_list, fb_format, &render_list_params, 0, render_list_params.element_count); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_ALL); + } + + RD::get_singleton()->draw_command_end_label(); // Render Transparent Subpass + } } - RD::get_singleton()->draw_command_end_label(); + if (render_buffer && !using_subpass_post_process) { + RD::get_singleton()->draw_command_begin_label("Post process pass"); + + // If we need extra effects we do this in its own pass + RENDER_TIMESTAMP("Tonemap"); - RD::get_singleton()->draw_command_begin_label("Resolve"); + _render_buffers_post_process_and_tonemap(p_render_data); - if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa, render_buffer->color); + RD::get_singleton()->draw_command_end_label(); // Post process pass } - RD::get_singleton()->draw_command_end_label(); + if (render_buffer) { + _disable_clear_request(p_render_data); + } } /* these are being called from RendererSceneRenderRD::_pre_opaque_render */ @@ -635,7 +877,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, true); uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); - _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); + _fill_element_info(RENDER_LIST_SECONDARY, render_list_from, render_list_size); { //regular forward for now @@ -713,7 +955,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); + _fill_element_info(RENDER_LIST_SECONDARY); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); @@ -754,7 +996,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<GeometryInstance *> &p_in PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL; _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); + _fill_element_info(RENDER_LIST_SECONDARY); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); @@ -827,7 +1069,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode); render_list[RENDER_LIST_SECONDARY].sort_by_key(); - _fill_instance_data(RENDER_LIST_SECONDARY); + _fill_element_info(RENDER_LIST_SECONDARY); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_SECONDARY, nullptr, RID()); @@ -1413,9 +1655,7 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER); } -void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { - // !BAS! Rename this to make clear this is not the same as with the forward renderer and remove p_update_buffer? - +void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) { RenderList *rl = &render_list[p_render_list]; uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); @@ -1669,7 +1909,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr prev_index_array_rd = index_array_rd; } - RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe); + RID pipeline_rd = pipeline->get_render_pipeline(vertex_format, framebuffer_format, p_params->force_wireframe, p_params->subpass); if (pipeline_rd != prev_pipeline_rd) { // checking with prev shader does not make so much sense, as @@ -1684,8 +1924,8 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr } if (material_uniform_set != prev_material_uniform_set) { - //update uniform set - if (material_uniform_set.is_valid()) { + // Update uniform set. + if (RD::get_singleton()->uniform_set_is_valid(material_uniform_set)) { // Material may not have a uniform set. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_uniform_set, MATERIAL_UNIFORM_SET); } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 973925d562..b981592840 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -92,6 +92,18 @@ protected: /* Render Buffer */ + // We can have: + // - 4 subpasses combining the full render cycle + // - 3 subpasses + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer) + // - 2 subpasses + 1 normal pass for transparent + 1 normal pass for tonemapping/glow/dof/etc (using fb for 2D buffer) + enum RenderBufferMobileFramebufferConfigType { + FB_CONFIG_ONE_PASS, // Single pass frame buffer for alpha pass + FB_CONFIG_TWO_SUBPASSES, // Opaque + Sky sub pass + FB_CONFIG_THREE_SUBPASSES, // Opaque + Sky + Alpha sub pass + FB_CONFIG_FOUR_SUBPASSES, // Opaque + Sky + Alpha sub pass + Tonemap pass + FB_CONFIG_MAX + }; + struct RenderBufferDataForwardMobile : public RenderBufferData { RID color; RID depth; @@ -104,12 +116,12 @@ protected: RID depth_msaa; // RID normal_roughness_buffer_msaa; - RID color_fb; + RID color_fbs[FB_CONFIG_MAX]; int width, height; uint32_t view_count; void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count); ~RenderBufferDataForwardMobile(); }; @@ -152,6 +164,7 @@ protected: RD::FramebufferFormatID framebuffer_format = 0; uint32_t element_offset = 0; uint32_t barrier = RD::BARRIER_MASK_ALL; + uint32_t subpass = 0; RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { elements = p_elements; @@ -195,7 +208,7 @@ protected: virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override; void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false); - void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); + void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1); // void _update_instance_data_buffer(RenderListType p_render_list); static RenderForwardMobile *singleton; @@ -576,6 +589,8 @@ protected: void _update_shader_quality_settings() override; public: + virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth) override; + static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker); static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 18c1fe02a0..14b2768c29 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -480,6 +480,10 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend case Item::Command::TYPE_RECT: { const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c); + if (rect->flags & CANVAS_RECT_TILE) { + current_repeat = RenderingServer::CanvasItemTextureRepeat::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED; + } + //bind pipeline { RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format); @@ -1089,7 +1093,8 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co if (material_data) { if (material_data->shader_data->version.is_valid() && material_data->shader_data->valid) { pipeline_variants = &material_data->shader_data->pipeline_variants; - if (material_data->uniform_set.is_valid()) { + // Update uniform set. + if (RD::get_singleton()->uniform_set_is_valid(material_data->uniform_set)) { // Material may not have a uniform set. RD::get_singleton()->draw_list_bind_uniform_set(draw_list, material_data->uniform_set, MATERIAL_UNIFORM_SET); } } else { diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 15b3b77ed9..8639362da9 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -80,7 +80,7 @@ protected: Map<RID, RID> render_target_descriptors; double time; - float delta; + double delta; static uint64_t frame; @@ -100,7 +100,7 @@ public: void finalize(); _ALWAYS_INLINE_ uint64_t get_frame_number() const { return frame; } - _ALWAYS_INLINE_ float get_frame_delta_time() const { return delta; } + _ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; } _ALWAYS_INLINE_ double get_total_time() const { return time; } static Error is_viable() { diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index e3516df800..5b734fc603 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -679,10 +679,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc for (int i = 0; i < atlas->count; i++) { atlas->reflections.write[i].data.update_reflection_data(storage, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format()); for (int j = 0; j < 6; j++) { - Vector<RID> fb; - fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]); - fb.push_back(atlas->depth_buffer); - atlas->reflections.write[i].fbs[j] = RD::get_singleton()->framebuffer_create(fb); + atlas->reflections.write[i].fbs[j] = reflection_probe_create_framebuffer(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j], atlas->depth_buffer); } } @@ -728,6 +725,13 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc return true; } +RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID p_depth) { + Vector<RID> fb; + fb.push_back(p_color); + fb.push_back(p_depth); + return RD::get_singleton()->framebuffer_create(fb); +} + bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND_V(!rpi, false); @@ -1996,6 +2000,75 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende storage->render_target_disable_clear_request(rb->render_target); } +void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data) { + RD::get_singleton()->draw_command_begin_label("Post Process Subpass"); + + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + ERR_FAIL_COND(!rb); + + RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment); + + bool can_use_effects = rb->width >= 8 && rb->height >= 8; + + RENDER_TIMESTAMP("Tonemap"); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass(); + + EffectsRD::TonemapSettings tonemap; + + if (env) { + tonemap.tonemap_mode = env->tone_mapper; + tonemap.exposure = env->exposure; + tonemap.white = env->white; + } + + // We don't support glow or auto exposure here, if they are needed, don't use subpasses! + // The problem is that we need to use the result so far and process them before we can + // apply this to our results. + if (can_use_effects && env && env->glow_enabled) { + ERR_FAIL_MSG("Glow is not supported when using subpasses."); + } + if (can_use_effects && env && env->auto_exposure) { + ERR_FAIL_MSG("Glow is not supported when using subpasses."); + } + + tonemap.use_glow = false; + tonemap.glow_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + tonemap.use_auto_exposure = false; + tonemap.exposure_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_WHITE); + + tonemap.use_color_correction = false; + tonemap.use_1d_color_correction = false; + tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); + + if (can_use_effects && env) { + tonemap.use_bcs = env->adjustments_enabled; + tonemap.brightness = env->adjustments_brightness; + tonemap.contrast = env->adjustments_contrast; + tonemap.saturation = env->adjustments_saturation; + if (env->adjustments_enabled && env->color_correction.is_valid()) { + tonemap.use_color_correction = true; + tonemap.use_1d_color_correction = env->use_1d_color_correction; + tonemap.color_correction_texture = storage->texture_get_rd_texture(env->color_correction); + } + } + + tonemap.use_debanding = rb->use_debanding; + tonemap.texture_size = Vector2i(rb->width, rb->height); + + tonemap.view_count = p_render_data->view_count; + + storage->get_effects()->tonemapper(draw_list, p_source_texture, RD::get_singleton()->framebuffer_get_format(p_framebuffer), tonemap); + + RD::get_singleton()->draw_command_end_label(); +} + +void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_data) { + RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + ERR_FAIL_COND(!rb); + + storage->render_target_disable_clear_request(rb->render_target); +} + void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) { EffectsRD *effects = storage->get_effects(); @@ -2283,12 +2356,11 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.width = rb->width; tf.height = rb->height; tf.array_layers = rb->view_count; // create a layer for every view - tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); + tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { - tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0); - } else { - tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; + tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; } + tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } @@ -2326,7 +2398,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count); } - rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count); + RID target_texture = storage->render_target_get_rd_texture(rb->render_target); + rb->data->configure(rb->texture, rb->depth_texture, target_texture, p_width, p_height, p_msaa, p_view_count); if (is_clustered_enabled()) { rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); @@ -3846,9 +3919,28 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData _render_scene(&render_data, clear_color); if (p_render_buffers.is_valid()) { - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || debug_draw == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { + /* + _debug_draw_cluster(p_render_buffers); + + RENDER_TIMESTAMP("Tonemap"); + + _render_buffers_post_process_and_tonemap(&render_data); + */ + + _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex); + if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) { + rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture); + } + } +} + +void RendererSceneRenderRD::_debug_draw_cluster(RID p_render_buffers) { + if (p_render_buffers.is_valid() && current_cluster_builder != nullptr) { + RS::ViewportDebugDraw dd = get_debug_draw_mode(); + + if (dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS || dd == RS::VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES) { ClusterBuilderRD::ElementType elem_type = ClusterBuilderRD::ELEMENT_TYPE_MAX; - switch (debug_draw) { + switch (dd) { case RS::VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS: elem_type = ClusterBuilderRD::ELEMENT_TYPE_OMNI_LIGHT; break; @@ -3864,17 +3956,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData default: { } } - if (current_cluster_builder != nullptr) { - current_cluster_builder->debug(elem_type); - } - } - - RENDER_TIMESTAMP("Tonemap"); - - _render_buffers_post_process_and_tonemap(&render_data); - _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex); - if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) { - rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture); + current_cluster_builder->debug(elem_type); } } } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index bb06eb608f..336dd6e1a7 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -95,7 +95,7 @@ protected: double time_step = 0; struct RenderBufferData { - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0; + virtual void configure(RID p_color_buffer, RID p_depth_buffer, RID p_target_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0; virtual ~RenderBufferData() {} }; virtual RenderBufferData *_create_render_buffer_data() = 0; @@ -117,6 +117,7 @@ protected: virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0; void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); + void _debug_draw_cluster(RID p_render_buffers); RenderBufferData *render_buffers_get_data(RID p_render_buffers); @@ -133,6 +134,10 @@ protected: void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); + void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data); + void _post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data); + void _disable_clear_request(const RenderDataRD *p_render_data); + // needed for a single argument calls (material and uv2) PagedArrayPool<GeometryInstance *> cull_argument_pool; PagedArray<GeometryInstance *> cull_argument; //need this to exist @@ -146,7 +151,7 @@ protected: } else { return nullptr; } - } + }; //used for mobile renderer mostly @@ -524,7 +529,6 @@ private: void _allocate_luminance_textures(RenderBuffers *rb); void _render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer); - void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data); /* Cluster */ @@ -923,6 +927,12 @@ public: virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override; virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override; + bool camera_effects_uses_dof(RID p_camera_effects) { + CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); + + return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0; + } + virtual RID light_instance_create(RID p_light) override; virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; @@ -1065,6 +1075,7 @@ public: virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth); virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; uint32_t reflection_probe_instance_get_resolution(RID p_instance); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index cadf759ec3..9331cab090 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -283,14 +283,17 @@ void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_ RD::DrawListID draw_list = p_list; - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format)); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format, false, RD::get_singleton()->draw_list_get_current_pass())); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0); - if (p_uniform_set.is_valid()) { //material may not have uniform set - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1); + // Update uniform sets. + { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0); + if (RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { // Material may not have a uniform set. + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1); + } + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); } - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -1277,12 +1280,11 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM RD::DrawListID cubemap_draw_list; for (int i = 0; i < 6; i++) { - Transform3D local_view; - local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); + Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd); cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } RD::get_singleton()->draw_command_end_label(); @@ -1297,12 +1299,11 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM RD::DrawListID cubemap_draw_list; for (int i = 0; i < 6; i++) { - Transform3D local_view; - local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); + Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd); cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } RD::get_singleton()->draw_command_end_label(); @@ -1313,12 +1314,11 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap"); for (int i = 0; i < 6; i++) { - Transform3D local_view; - local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); + Basis local_view = Basis::looking_at(view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd); cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } RD::get_singleton()->draw_command_end_label(); @@ -1467,6 +1467,179 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont RD::get_singleton()->draw_list_end(); } +void RendererSceneSkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) { + ERR_FAIL_COND(!p_env); + + ERR_FAIL_COND(p_view_count == 0); + ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); + + Sky *sky = get_sky(p_env->sky); + ERR_FAIL_COND(!sky); + + SkyMaterialData *material = nullptr; + RID sky_material; + + RS::EnvironmentBG background = p_env->background; + + if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { + ERR_FAIL_COND(!sky); + sky_material = sky_get_material(p_env->sky); + + if (sky_material.is_valid()) { + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + } + } + + if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { + sky_material = sky_scene_state.fog_material; + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + } + + ERR_FAIL_COND(!material); + + SkyShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + Basis sky_transform = p_env->sky_orientation; + sky_transform.invert(); + + float multiplier = p_env->bg_energy; + float custom_fov = p_env->sky_custom_fov; + + // Camera + CameraMatrix camera; + uint32_t view_count = p_view_count; + const CameraMatrix *projections = p_projections; + + if (custom_fov) { + // With custom fov we don't support stereo... + float near_plane = p_projections[0].get_z_near(); + float far_plane = p_projections[0].get_z_far(); + float aspect = p_projections[0].get_aspect(); + + camera.set_perspective(custom_fov, aspect, near_plane, far_plane); + + view_count = 1; + projections = &camera; + } + + sky_transform = p_transform.basis * sky_transform; + + if (shader_data->uses_quarter_res) { + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES]; + + RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); + + Vector<Color> clear_colors; + clear_colors.push_back(Color(0.0, 0.0, 0.0)); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin); + RD::get_singleton()->draw_list_end(); + } + + if (shader_data->uses_half_res) { + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES]; + + RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); + + Vector<Color> clear_colors; + clear_colors.push_back(Color(0.0, 0.0, 0.0)); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin); + RD::get_singleton()->draw_list_end(); + } +} + +void RendererSceneSkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) { + ERR_FAIL_COND(!p_env); + + ERR_FAIL_COND(p_view_count == 0); + ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); + + Sky *sky = get_sky(p_env->sky); + ERR_FAIL_COND(!sky); + + SkyMaterialData *material = nullptr; + RID sky_material; + + RS::EnvironmentBG background = p_env->background; + + if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { + ERR_FAIL_COND(!sky); + sky_material = sky_get_material(p_env->sky); + + if (sky_material.is_valid()) { + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + sky_material = sky_shader.default_material; + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + } + } + + if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { + sky_material = sky_scene_state.fog_material; + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + } + + ERR_FAIL_COND(!material); + + SkyShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + Basis sky_transform = p_env->sky_orientation; + sky_transform.invert(); + + float multiplier = p_env->bg_energy; + float custom_fov = p_env->sky_custom_fov; + + // Camera + CameraMatrix camera; + uint32_t view_count = p_view_count; + const CameraMatrix *projections = p_projections; + + if (custom_fov) { + // With custom fov we don't support stereo... + float near_plane = p_projections[0].get_z_near(); + float far_plane = p_projections[0].get_z_far(); + float aspect = p_projections[0].get_aspect(); + + camera.set_perspective(custom_fov, aspect, near_plane, far_plane); + + view_count = 1; + projections = &camera; + } + + sky_transform = p_transform.basis * sky_transform; + + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND]; + + RID texture_uniform_set; + if (sky) { + texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd); + } else { + texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set; + } + + _render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin); +} + void RendererSceneSkyRD::invalidate_sky(Sky *p_sky) { if (!p_sky->dirty) { p_sky->dirty = true; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 7e0b01d58e..7b670bddd5 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -295,6 +295,8 @@ public: void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time); void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time); + void update_res_buffers(RendererSceneEnvironmentRD *p_env, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time); + void draw(RD::DrawListID p_draw_list, RendererSceneEnvironmentRD *p_env, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time); void invalidate_sky(Sky *p_sky); void update_dirty_skys(); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index d5c7db6fd2..5b845cbb88 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -4091,7 +4091,7 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); } -void RendererStorageRD::particles_set_lifetime(RID p_particles, float p_lifetime) { +void RendererStorageRD::particles_set_lifetime(RID p_particles, double p_lifetime) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->lifetime = p_lifetime; @@ -4103,7 +4103,7 @@ void RendererStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) particles->one_shot = p_one_shot; } -void RendererStorageRD::particles_set_pre_process_time(RID p_particles, float p_time) { +void RendererStorageRD::particles_set_pre_process_time(RID p_particles, double p_time) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); particles->pre_process_time = p_time; @@ -4126,7 +4126,7 @@ void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -void RendererStorageRD::particles_set_speed_scale(RID p_particles, float p_scale) { +void RendererStorageRD::particles_set_speed_scale(RID p_particles, double p_scale) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -4442,7 +4442,7 @@ void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool particles->sdf_collision_texture = p_texture; } -void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta) { +void RendererStorageRD::_particles_process(Particles *p_particles, double p_delta) { if (p_particles->particles_material_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(p_particles->particles_material_uniform_set)) { Vector<RD::Uniform> uniforms; @@ -4491,7 +4491,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta p_particles->particles_material_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, particles_shader.default_shader_rd, 1); } - float new_phase = Math::fmod((float)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, (float)1.0); + double new_phase = Math::fmod((double)p_particles->phase + (p_delta / p_particles->lifetime) * p_particles->speed_scale, 1.0); //move back history (if there is any) for (uint32_t i = p_particles->frame_history.size() - 1; i > 0; i--) { @@ -5131,14 +5131,14 @@ void RendererStorageRD::update_particles() { bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0; if (particles->clear && particles->pre_process_time > 0.0) { - float frame_time; + double frame_time; if (fixed_fps > 0) { frame_time = 1.0 / fixed_fps; } else { frame_time = 1.0 / 30.0; } - float todo = particles->pre_process_time; + double todo = particles->pre_process_time; while (todo >= 0) { _particles_process(particles, frame_time); @@ -5147,8 +5147,8 @@ void RendererStorageRD::update_particles() { } if (fixed_fps > 0) { - float frame_time; - float decr; + double frame_time; + double decr; if (zero_time_scale) { frame_time = 0.0; decr = 1.0 / fixed_fps; @@ -5156,13 +5156,13 @@ void RendererStorageRD::update_particles() { frame_time = 1.0 / fixed_fps; decr = frame_time; } - float delta = RendererCompositorRD::singleton->get_frame_delta_time(); + double delta = RendererCompositorRD::singleton->get_frame_delta_time(); if (delta > 0.1) { //avoid recursive stalls if fps goes below 10 delta = 0.1; } else if (delta <= 0.0) { //unlikely but.. delta = 0.001; } - float todo = particles->frame_remainder + delta; + double todo = particles->frame_remainder + delta; while (todo >= frame_time) { _particles_process(particles, frame_time); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index b290c07705..71c3d8b09a 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -715,12 +715,12 @@ private: struct Particles { RS::ParticlesMode mode = RS::PARTICLES_MODE_3D; bool inactive = true; - float inactive_time = 0.0; + double inactive_time = 0.0; bool emitting = false; bool one_shot = false; int amount = 0; - float lifetime = 1.0; - float pre_process_time = 0.0; + double lifetime = 1.0; + double pre_process_time = 0.0; float explosiveness = 0.0; float randomness = 0.0; bool restart_request = false; @@ -773,12 +773,12 @@ private: uint32_t cycle_number = 0; - float speed_scale = 1.0; + double speed_scale = 1.0; int fixed_fps = 30; bool interpolate = true; bool fractional_delta = false; - float frame_remainder = 0; + double frame_remainder = 0; float collision_base_size = 0.01; bool clear = true; @@ -805,14 +805,14 @@ private: } }; - void _particles_process(Particles *p_particles, float p_delta); + void _particles_process(Particles *p_particles, double p_delta); void _particles_allocate_emission_buffer(Particles *particles); void _particles_free_data(Particles *particles); void _particles_update_buffers(Particles *particles); struct ParticlesShader { struct PushConstant { - float lifetime; + double lifetime; uint32_t clear; uint32_t total_particles; uint32_t trail_size; @@ -2144,13 +2144,13 @@ public: void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode); void particles_set_emitting(RID p_particles, bool p_emitting); void particles_set_amount(RID p_particles, int p_amount); - void particles_set_lifetime(RID p_particles, float p_lifetime); + void particles_set_lifetime(RID p_particles, double p_lifetime); void particles_set_one_shot(RID p_particles, bool p_one_shot); - void particles_set_pre_process_time(RID p_particles, float p_time); + void particles_set_pre_process_time(RID p_particles, double p_time); void particles_set_explosiveness_ratio(RID p_particles, float p_ratio); void particles_set_randomness_ratio(RID p_particles, float p_ratio); void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb); - void particles_set_speed_scale(RID p_particles, float p_scale); + void particles_set_speed_scale(RID p_particles, double p_scale); void particles_set_use_local_coordinates(RID p_particles, bool p_enable); void particles_set_process_material(RID p_particles, RID p_material); void particles_set_fixed_fps(RID p_particles, int p_fps); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index b3a349c948..4f140dd10d 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -466,6 +466,11 @@ layout(location = 0) out vec4 frag_color; #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +/* Make a default specular mode SPECULAR_SCHLICK_GGX. */ +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON) +#define SPECULAR_SCHLICK_GGX +#endif + #include "scene_forward_lights_inc.glsl" #include "scene_forward_gi_inc.glsl" @@ -907,6 +912,8 @@ void main() { specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + specular_light *= horizon * horizon; specular_light *= scene_data.ambient_light_color_energy.a; } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 70900a847c..681656e1d5 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -491,6 +491,11 @@ layout(location = 0) out vec4 frag_color; #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) +/* Make a default specular mode SPECULAR_SCHLICK_GGX. */ +#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) && !defined(SPECULAR_PHONG) && !defined(SPECULAR_TOON) +#define SPECULAR_SCHLICK_GGX +#endif + #include "scene_forward_lights_inc.glsl" #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) @@ -843,6 +848,8 @@ void main() { specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); + specular_light *= horizon * horizon; specular_light *= scene_data.ambient_light_color_energy.a; } diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 23f83b3b9c..3c685c25b9 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -35,11 +35,15 @@ void main() { layout(location = 0) in vec2 uv_interp; -#ifdef MULTIVIEW +#ifdef SUBPASS +layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color; +#else +#if MULTIVIEW layout(set = 0, binding = 0) uniform sampler2DArray source_color; #else layout(set = 0, binding = 0) uniform sampler2D source_color; #endif +#endif layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; #ifdef USE_1D_LUT @@ -180,10 +184,6 @@ vec3 tonemap_aces(vec3 color, float white) { } vec3 tonemap_reinhard(vec3 color, float white) { - // Ensure color values are positive. - // They can be negative in the case of negative lights, which leads to undesired behavior. - color = max(vec3(0.0), color); - return (white * color + color) / (color * white + white); } @@ -207,7 +207,7 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o return tonemap_reinhard(color, white); } else if (params.tonemapper == TONEMAPPER_FILMIC) { return tonemap_filmic(color, white); - } else { //aces + } else { // TONEMAPPER_ACES return tonemap_aces(color, white); } } @@ -291,6 +291,7 @@ vec3 apply_color_correction(vec3 color) { } #endif +#ifndef SUBPASS vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { const float FXAA_REDUCE_MIN = (1.0 / 128.0); const float FXAA_REDUCE_MUL = (1.0 / 8.0); @@ -346,6 +347,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { return rgbB; } } +#endif // !SUBPASS // From http://alex.vlachos.com/graphics/Alex_Vlachos_Advanced_VR_Rendering_GDC2015.pdf // and https://www.shadertoy.com/view/MslGR8 (5th one starting from the bottom) @@ -360,7 +362,10 @@ vec3 screen_space_dither(vec2 frag_coord) { } void main() { -#ifdef MULTIVIEW +#ifdef SUBPASS + // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer + vec3 color = subpassLoad(input_color).rgb; +#elif MULTIVIEW vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb; #else vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; @@ -370,14 +375,16 @@ void main() { float exposure = params.exposure; +#ifndef SUBPASS if (params.use_auto_exposure) { exposure *= 1.0 / (texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / params.auto_exposure_grey); } +#endif color *= exposure; // Early Tonemap & SRGB Conversion - +#ifndef SUBPASS if (params.use_glow && params.glow_mode == GLOW_MODE_MIX) { vec3 glow = gather_glow(source_glow, uv_interp); color.rgb = mix(color.rgb, glow, params.glow_intensity); @@ -386,15 +393,21 @@ void main() { if (params.use_fxaa) { color = do_fxaa(color, exposure, uv_interp); } +#endif + if (params.use_debanding) { // For best results, debanding should be done before tonemapping. // Otherwise, we're adding noise to an already-quantized image. color += screen_space_dither(gl_FragCoord.xy); } - color = apply_tonemapping(color, params.white); + + // Ensure color values passed to tonemappers are positive. + // They can be negative in the case of negative lights, which leads to undesired behavior. + color = apply_tonemapping(max(vec3(0.0), color), params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion +#ifndef SUBPASS // Glow if (params.use_glow && params.glow_mode != GLOW_MODE_MIX) { @@ -406,6 +419,7 @@ void main() { color = apply_glow(color, glow); } +#endif // Additional effects diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 83d1b33bf2..6357a6f4c2 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1866,7 +1866,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) //rotate it Basis rot = lightmap->transform.basis.orthonormalized(); for (int i = 0; i < 3; i++) { - float csh[9]; + real_t csh[9]; for (int j = 0; j < 9; j++) { csh[j] = sh[j][i]; } @@ -1878,7 +1878,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); - float blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); + real_t blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); //make blend more rounded blend = Math::lerp(inner_pos.length(), blend, blend); blend *= blend; diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index 1d0f53c0bf..e06b3ba153 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -60,7 +60,7 @@ public: void update_mips(); - _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const { + _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const CameraMatrix &p_cam_projection, real_t p_near) const { if (is_empty()) { return false; } diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index b9bc349f79..6ffbdbf685 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -468,13 +468,13 @@ public: virtual bool particles_get_emitting(RID p_particles) = 0; virtual void particles_set_amount(RID p_particles, int p_amount) = 0; - virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0; + virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0; virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; - virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0; + virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0; virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0; - virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; + virtual void particles_set_speed_scale(RID p_particles, double p_scale) = 0; virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 1dfe2803b4..bb9ffffe8a 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -739,7 +739,7 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_UPDATE_BIT); BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_COPY_FROM_BIT); BIND_ENUM_CONSTANT(TEXTURE_USAGE_CAN_COPY_TO_BIT); - BIND_ENUM_CONSTANT(TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT); + BIND_ENUM_CONSTANT(TEXTURE_USAGE_INPUT_ATTACHMENT_BIT); BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_IDENTITY); BIND_ENUM_CONSTANT(TEXTURE_SWIZZLE_ZERO); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index eaf1ace798..bb028cb84c 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -422,7 +422,7 @@ public: TEXTURE_USAGE_CAN_UPDATE_BIT = (1 << 6), TEXTURE_USAGE_CAN_COPY_FROM_BIT = (1 << 7), TEXTURE_USAGE_CAN_COPY_TO_BIT = (1 << 8), - TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT = (1 << 9), + TEXTURE_USAGE_INPUT_ATTACHMENT_BIT = (1 << 9), }; enum TextureSwizzle { @@ -1065,6 +1065,7 @@ public: virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0; virtual void draw_list_disable_scissor(DrawListID p_list) = 0; + virtual uint32_t draw_list_get_current_pass() = 0; virtual DrawListID draw_list_switch_to_next_pass() = 0; virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) = 0; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index c79dfb1649..bed6ade1f6 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -134,8 +134,8 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { } if (RSG::storage->capturing_timestamps) { - new_profile.write[i].gpu_msec = float((time_gpu - base_gpu) / 1000) / 1000.0; - new_profile.write[i].cpu_msec = float(time_cpu - base_cpu) / 1000.0; + new_profile.write[i].gpu_msec = double((time_gpu - base_gpu) / 1000) / 1000.0; + new_profile.write[i].cpu_msec = double(time_cpu - base_cpu) / 1000.0; new_profile.write[i].name = RSG::storage->get_captured_timestamp_name(i); } } @@ -149,7 +149,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { if (print_frame_profile_ticks_from == 0) { print_frame_profile_ticks_from = OS::get_singleton()->get_ticks_usec(); } - float total_time = 0.0; + double total_time = 0.0; for (int i = 0; i < frame_profile.size() - 1; i++) { String name = frame_profile[i].name; @@ -157,7 +157,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { continue; } - float time = frame_profile[i + 1].gpu_msec - frame_profile[i].gpu_msec; + double time = frame_profile[i + 1].gpu_msec - frame_profile[i].gpu_msec; if (name[0] != '<' && name[0] != '>') { if (print_gpu_profile_task_time.has(name)) { @@ -179,7 +179,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { float print_threshold = 0.01; for (OrderedHashMap<String, float>::Element E = print_gpu_profile_task_time.front(); E; E = E.next()) { - float time = E.value() / float(print_frame_profile_frame_count); + double time = E.value() / double(print_frame_profile_frame_count); if (time > print_threshold) { print_line("\t-" + E.key() + ": " + rtos(time) + "ms"); } @@ -193,7 +193,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::storage->update_memory_info(); } -float RenderingServerDefault::get_frame_setup_time_cpu() const { +double RenderingServerDefault::get_frame_setup_time_cpu() const { return frame_setup_time; } diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 282b0564da..381f38d80e 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -71,7 +71,7 @@ class RenderingServerDefault : public RenderingServer { uint64_t frame_profile_frame; Vector<FrameProfileArea> frame_profile; - float frame_setup_time = 0; + double frame_setup_time = 0; //for printing bool print_gpu_profile = false; @@ -440,13 +440,13 @@ public: FUNC2(particles_set_emitting, RID, bool) FUNC1R(bool, particles_get_emitting, RID) FUNC2(particles_set_amount, RID, int) - FUNC2(particles_set_lifetime, RID, float) + FUNC2(particles_set_lifetime, RID, double) FUNC2(particles_set_one_shot, RID, bool) - FUNC2(particles_set_pre_process_time, RID, float) + FUNC2(particles_set_pre_process_time, RID, double) FUNC2(particles_set_explosiveness_ratio, RID, float) FUNC2(particles_set_randomness_ratio, RID, float) FUNC2(particles_set_custom_aabb, RID, const AABB &) - FUNC2(particles_set_speed_scale, RID, float) + FUNC2(particles_set_speed_scale, RID, double) FUNC2(particles_set_use_local_coordinates, RID, bool) FUNC2(particles_set_process_material, RID, RID) FUNC2(particles_set_fixed_fps, RID, int) @@ -574,8 +574,8 @@ public: FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw) FUNC2(viewport_set_measure_render_time, RID, bool) - FUNC1RC(float, viewport_get_measured_render_time_cpu, RID) - FUNC1RC(float, viewport_get_measured_render_time_gpu, RID) + FUNC1RC(double, viewport_get_measured_render_time_cpu, RID) + FUNC1RC(double, viewport_get_measured_render_time_gpu, RID) FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID) @@ -890,7 +890,7 @@ public: /* TESTING */ - virtual float get_frame_setup_time_cpu() const override; + virtual double get_frame_setup_time_cpu() const override; virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) override; virtual void set_default_clear_color(const Color &p_color) override; diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 376d23ccb3..4488069698 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -31,18 +31,22 @@ #include "shader_types.h" #include "core/math/math_defs.h" -const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(RS::ShaderMode p_mode) { +const Map<StringName, ShaderLanguage::FunctionInfo> &ShaderTypes::get_functions(RS::ShaderMode p_mode) const { return shader_modes[p_mode].functions; } -const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) { +const Vector<StringName> &ShaderTypes::get_modes(RS::ShaderMode p_mode) const { return shader_modes[p_mode].modes; } -const Set<String> &ShaderTypes::get_types() { +const Set<String> &ShaderTypes::get_types() const { return shader_types; } +const List<String> &ShaderTypes::get_types_list() const { + return shader_types_list; +} + ShaderTypes *ShaderTypes::singleton = nullptr; static ShaderLanguage::BuiltInInfo constt(ShaderLanguage::DataType p_type) { @@ -440,8 +444,12 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass"); shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog"); - shader_types.insert("spatial"); - shader_types.insert("canvas_item"); - shader_types.insert("particles"); - shader_types.insert("sky"); + shader_types_list.push_back("spatial"); + shader_types_list.push_back("canvas_item"); + shader_types_list.push_back("particles"); + shader_types_list.push_back("sky"); + + for (int i = 0; i < shader_types_list.size(); i++) { + shader_types.insert(shader_types_list[i]); + } } diff --git a/servers/rendering/shader_types.h b/servers/rendering/shader_types.h index e59cef6b79..75a310a1b1 100644 --- a/servers/rendering/shader_types.h +++ b/servers/rendering/shader_types.h @@ -46,13 +46,15 @@ class ShaderTypes { static ShaderTypes *singleton; Set<String> shader_types; + List<String> shader_types_list; public: static ShaderTypes *get_singleton() { return singleton; } - const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode); - const Vector<StringName> &get_modes(RS::ShaderMode p_mode); - const Set<String> &get_types(); + const Map<StringName, ShaderLanguage::FunctionInfo> &get_functions(RS::ShaderMode p_mode) const; + const Vector<StringName> &get_modes(RS::ShaderMode p_mode) const; + const Set<String> &get_types() const; + const List<String> &get_types_list() const; ShaderTypes(); }; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 314b59869d..2da8e0f297 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -242,7 +242,7 @@ RID RenderingServer::_make_test_cube() { return test_cube; } -RID RenderingServer::make_sphere_mesh(int p_lats, int p_lons, float p_radius) { +RID RenderingServer::make_sphere_mesh(int p_lats, int p_lons, real_t p_radius) { Vector<Vector3> vertices; Vector<Vector3> normals; const double lat_step = Math_TAU / p_lats; @@ -412,26 +412,40 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint } break; case RS::ARRAY_TANGENT: { - ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); + Variant::Type type = p_arrays[ai].get_type(); + ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); + if (type == Variant::PACKED_FLOAT32_ARRAY) { + Vector<float> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const float *src = array.ptr(); - Vector<real_t> array = p_arrays[ai]; - - ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); - - const real_t *src = array.ptr(); + for (int i = 0; i < p_vertex_array_len; i++) { + uint32_t value = 0; + value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + if (src[i * 4 + 3] > 0) { + value |= 3 << 30; + } - for (int i = 0; i < p_vertex_array_len; i++) { - uint32_t value = 0; - value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); - value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; - value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - if (src[i * 4 + 3] > 0) { - value |= 3 << 30; + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } + } else { // if (type == Variant::PACKED_FLOAT64_ARRAY) + Vector<double> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER); + const double *src = array.ptr(); - memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + for (int i = 0; i < p_vertex_array_len; i++) { + uint32_t value = 0; + value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + if (src[i * 4 + 3] > 0) { + value |= 3 << 30; + } + memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); + } } - } break; case RS::ARRAY_COLOR: { ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_COLOR_ARRAY, ERR_INVALID_PARAMETER); @@ -543,27 +557,38 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint } break; case RS::ARRAY_WEIGHTS: { - ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); - + Variant::Type type = p_arrays[ai].get_type(); + ERR_FAIL_COND_V(type != Variant::PACKED_FLOAT32_ARRAY && type != Variant::PACKED_FLOAT64_ARRAY, ERR_INVALID_PARAMETER); uint32_t bone_count = (p_format & ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? 8 : 4; + if (type == Variant::PACKED_FLOAT32_ARRAY) { + Vector<float> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); + const float *src = array.ptr(); + { + uint16_t data[8]; + for (int i = 0; i < p_vertex_array_len; i++) { + for (uint32_t j = 0; j < bone_count; j++) { + data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535); + } - Vector<real_t> array = p_arrays[ai]; - - ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); - - const real_t *src = array.ptr(); - - { - uint16_t data[8]; - for (int i = 0; i < p_vertex_array_len; i++) { - for (uint32_t j = 0; j < bone_count; j++) { - data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535); + memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); } + } + } else { // if (type == Variant::PACKED_FLOAT64_ARRAY) + Vector<double> array = p_arrays[ai]; + ERR_FAIL_COND_V(array.size() != (int32_t)(p_vertex_array_len * bone_count), ERR_INVALID_PARAMETER); + const double *src = array.ptr(); + { + uint16_t data[8]; + for (int i = 0; i < p_vertex_array_len; i++) { + for (uint32_t j = 0; j < bone_count; j++) { + data[j] = CLAMP(src[i * bone_count + j] * 65535, 0, 65535); + } - memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); + memcpy(&sw[p_offsets[ai] + i * p_skin_stride], data, 2 * bone_count); + } } } - } break; case RS::ARRAY_BONES: { ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_INT32_ARRAY && p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 28aee1b575..6b789a6121 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -613,13 +613,13 @@ public: virtual void particles_set_emitting(RID p_particles, bool p_enable) = 0; virtual bool particles_get_emitting(RID p_particles) = 0; virtual void particles_set_amount(RID p_particles, int p_amount) = 0; - virtual void particles_set_lifetime(RID p_particles, float p_lifetime) = 0; + virtual void particles_set_lifetime(RID p_particles, double p_lifetime) = 0; virtual void particles_set_one_shot(RID p_particles, bool p_one_shot) = 0; - virtual void particles_set_pre_process_time(RID p_particles, float p_time) = 0; + virtual void particles_set_pre_process_time(RID p_particles, double p_time) = 0; virtual void particles_set_explosiveness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_randomness_ratio(RID p_particles, float p_ratio) = 0; virtual void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) = 0; - virtual void particles_set_speed_scale(RID p_particles, float p_scale) = 0; + virtual void particles_set_speed_scale(RID p_particles, double p_scale) = 0; virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; @@ -900,8 +900,8 @@ public: virtual void viewport_set_debug_draw(RID p_viewport, ViewportDebugDraw p_draw) = 0; virtual void viewport_set_measure_render_time(RID p_viewport, bool p_enable) = 0; - virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0; - virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0; + virtual double viewport_get_measured_render_time_cpu(RID p_viewport) const = 0; + virtual double viewport_get_measured_render_time_gpu(RID p_viewport) const = 0; /* SKY API */ @@ -1436,15 +1436,15 @@ public: struct FrameProfileArea { String name; - float gpu_msec; - float cpu_msec; + double gpu_msec; + double cpu_msec; }; virtual void set_frame_profiling_enabled(bool p_enable) = 0; virtual Vector<FrameProfileArea> get_frame_profile() = 0; virtual uint64_t get_frame_profile_frame() = 0; - virtual float get_frame_setup_time_cpu() const = 0; + virtual double get_frame_setup_time_cpu() const = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; @@ -1457,7 +1457,7 @@ public: virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; - virtual RID make_sphere_mesh(int p_lats, int p_lons, float p_radius); + virtual RID make_sphere_mesh(int p_lats, int p_lons, real_t p_radius); virtual void mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data); virtual void mesh_add_surface_from_planes(RID p_mesh, const Vector<Plane> &p_planes); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 1491368109..e32ea9cdea 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -314,8 +314,8 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control); ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL("")); - ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); - ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(VALIGN_CENTER)); + ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGN_CENTER)); ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr); ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent); diff --git a/servers/text_server.h b/servers/text_server.h index 4c2ada7fc9..d824504bf4 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -181,7 +181,7 @@ public: struct EmbeddedObject { int pos = 0; - VAlign inline_align = VALIGN_TOP; + InlineAlign inline_align = INLINE_ALIGN_CENTER; Rect2 rect; }; Map<Variant, EmbeddedObject> objects; @@ -332,8 +332,8 @@ public: virtual bool shaped_text_get_preserve_control(RID p_shaped) const = 0; virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") = 0; - virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) = 0; - virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) = 0; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) = 0; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) = 0; virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range. virtual RID shaped_text_get_parent(RID p_shaped) const = 0; diff --git a/tests/data/translations.csv b/tests/data/translations.csv index 4c9ad4996a..8cb7b800c5 100644 --- a/tests/data/translations.csv +++ b/tests/data/translations.csv @@ -1,3 +1,8 @@ keys,en,de GOOD_MORNING,"Good Morning","Guten Morgen" GOOD_EVENING,"Good Evening","" +Without quotes,"With, comma","With ""inner"" quotes","With ""inner"", quotes"","" and comma","With ""inner +split"" quotes and +line breaks","With \nnewline chars" +Some other~delimiter~should still work, shouldn't it? +What about tab separated lines, good? diff --git a/tests/test_file_access.h b/tests/test_file_access.h index cb74e08a0d..b3da16c1d1 100644 --- a/tests/test_file_access.h +++ b/tests/test_file_access.h @@ -37,12 +37,12 @@ namespace TestFileAccess { TEST_CASE("[FileAccess] CSV read") { - FileAccess *f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ); + FileAccessRef f = FileAccess::open(TestUtils::get_data_path("translations.csv"), FileAccess::READ); - Vector<String> header = f->get_csv_line(); // Default delimiter: "," + Vector<String> header = f->get_csv_line(); // Default delimiter: ",". REQUIRE(header.size() == 3); - Vector<String> row1 = f->get_csv_line(","); + Vector<String> row1 = f->get_csv_line(","); // Explicit delimiter, should be the same. REQUIRE(row1.size() == 3); CHECK(row1[0] == "GOOD_MORNING"); CHECK(row1[1] == "Good Morning"); @@ -53,12 +53,31 @@ TEST_CASE("[FileAccess] CSV read") { CHECK(row2[0] == "GOOD_EVENING"); CHECK(row2[1] == "Good Evening"); CHECK(row2[2] == ""); // Use case: not yet translated! - // https://github.com/godotengine/godot/issues/44269 CHECK_MESSAGE(row2[2] != "\"", "Should not parse empty string as a single double quote."); + Vector<String> row3 = f->get_csv_line(); + REQUIRE(row3.size() == 6); + CHECK(row3[0] == "Without quotes"); + CHECK(row3[1] == "With, comma"); + CHECK(row3[2] == "With \"inner\" quotes"); + CHECK(row3[3] == "With \"inner\", quotes\",\" and comma"); + CHECK(row3[4] == "With \"inner\nsplit\" quotes and\nline breaks"); + CHECK(row3[5] == "With \\nnewline chars"); // Escaped, not an actual newline. + + Vector<String> row4 = f->get_csv_line("~"); // Custom delimiter, makes inline commas easier. + REQUIRE(row4.size() == 3); + CHECK(row4[0] == "Some other"); + CHECK(row4[1] == "delimiter"); + CHECK(row4[2] == "should still work, shouldn't it?"); + + Vector<String> row5 = f->get_csv_line("\t"); // Tab separated variables. + REQUIRE(row5.size() == 3); + CHECK(row5[0] == "What about"); + CHECK(row5[1] == "tab separated"); + CHECK(row5[2] == "lines, good?"); + f->close(); - memdelete(f); } } // namespace TestFileAccess diff --git a/tests/test_math.cpp b/tests/test_math.cpp index d0b9fdef4b..a44040dfe2 100644 --- a/tests/test_math.cpp +++ b/tests/test_math.cpp @@ -589,13 +589,13 @@ MainLoop *test() { { Vector3 v(1, 2, 3); v.normalize(); - float a = 0.3; + real_t a = 0.3; Basis m(v, a); Vector3 v2(7, 3, 1); v2.normalize(); - float a2 = 0.8; + real_t a2 = 0.8; Basis m2(v2, a2); diff --git a/tests/test_render.cpp b/tests/test_render.cpp index beff86dd83..21b4da9b3b 100644 --- a/tests/test_render.cpp +++ b/tests/test_render.cpp @@ -184,7 +184,7 @@ public: light = vs->instance_create2(lightaux, scenario); Transform3D lla; //lla.set_look_at(Vector3(),Vector3(1, -1, 1)); - lla.set_look_at(Vector3(), Vector3(0.0, -0.836026, -0.548690)); + lla.basis = Basis::looking_at(Vector3(0.0, -0.836026, -0.548690)); vs->instance_set_transform(light, lla); |