summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub22
-rw-r--r--core/config/engine.cpp4
-rw-r--r--core/config/engine.h14
-rw-r--r--core/config/project_settings.cpp242
-rw-r--r--core/config/project_settings.h18
-rw-r--r--core/core_bind.cpp165
-rw-r--r--core/core_bind.h41
-rw-r--r--core/core_constants.cpp22
-rw-r--r--core/core_constants.h4
-rw-r--r--core/core_string_names.cpp7
-rw-r--r--core/core_string_names.h5
-rw-r--r--core/crypto/SCsub15
-rw-r--r--core/crypto/aes_context.cpp4
-rw-r--r--core/crypto/aes_context.h4
-rw-r--r--core/crypto/crypto.cpp6
-rw-r--r--core/crypto/crypto.h6
-rw-r--r--core/crypto/crypto_core.cpp4
-rw-r--r--core/crypto/crypto_core.h4
-rw-r--r--core/crypto/hashing_context.cpp4
-rw-r--r--core/crypto/hashing_context.h4
-rw-r--r--core/debugger/debugger_marshalls.cpp4
-rw-r--r--core/debugger/debugger_marshalls.h4
-rw-r--r--core/debugger/engine_debugger.cpp12
-rw-r--r--core/debugger/engine_debugger.h10
-rw-r--r--core/debugger/local_debugger.cpp14
-rw-r--r--core/debugger/local_debugger.h4
-rw-r--r--core/debugger/remote_debugger.cpp11
-rw-r--r--core/debugger/remote_debugger.h4
-rw-r--r--core/debugger/remote_debugger_peer.cpp16
-rw-r--r--core/debugger/remote_debugger_peer.h6
-rw-r--r--core/debugger/script_debugger.cpp4
-rw-r--r--core/debugger/script_debugger.h4
-rw-r--r--core/doc_data.cpp4
-rw-r--r--core/doc_data.h4
-rw-r--r--core/error/error_list.h4
-rw-r--r--core/error/error_macros.cpp4
-rw-r--r--core/error/error_macros.h18
-rw-r--r--core/input/default_controller_mappings.h4
-rw-r--r--core/input/gamecontrollerdb.txt116
-rw-r--r--core/input/godotcontrollerdb.txt27
-rw-r--r--core/input/input.cpp97
-rw-r--r--core/input/input.h17
-rw-r--r--core/input/input_event.cpp94
-rw-r--r--core/input/input_event.h26
-rw-r--r--core/input/input_map.cpp556
-rw-r--r--core/input/input_map.h21
-rw-r--r--core/io/compression.cpp4
-rw-r--r--core/io/compression.h4
-rw-r--r--core/io/config_file.cpp6
-rw-r--r--core/io/config_file.h4
-rw-r--r--core/io/dtls_server.cpp4
-rw-r--r--core/io/dtls_server.h4
-rw-r--r--core/io/file_access_compressed.cpp8
-rw-r--r--core/io/file_access_compressed.h4
-rw-r--r--core/io/file_access_encrypted.cpp10
-rw-r--r--core/io/file_access_encrypted.h4
-rw-r--r--core/io/file_access_memory.cpp4
-rw-r--r--core/io/file_access_memory.h4
-rw-r--r--core/io/file_access_network.cpp19
-rw-r--r--core/io/file_access_network.h6
-rw-r--r--core/io/file_access_pack.cpp6
-rw-r--r--core/io/file_access_pack.h6
-rw-r--r--core/io/file_access_zip.cpp4
-rw-r--r--core/io/file_access_zip.h4
-rw-r--r--core/io/http_client.cpp15
-rw-r--r--core/io/http_client.h4
-rw-r--r--core/io/image.cpp70
-rw-r--r--core/io/image.h14
-rw-r--r--core/io/image_loader.cpp6
-rw-r--r--core/io/image_loader.h6
-rw-r--r--core/io/ip.cpp54
-rw-r--r--core/io/ip.h4
-rw-r--r--core/io/ip_address.cpp4
-rw-r--r--core/io/ip_address.h4
-rw-r--r--core/io/json.cpp54
-rw-r--r--core/io/json.h4
-rw-r--r--core/io/logger.cpp30
-rw-r--r--core/io/logger.h8
-rw-r--r--core/io/marshalls.cpp4
-rw-r--r--core/io/marshalls.h4
-rw-r--r--core/io/multiplayer_api.cpp4
-rw-r--r--core/io/multiplayer_api.h4
-rw-r--r--core/io/net_socket.cpp4
-rw-r--r--core/io/net_socket.h4
-rw-r--r--core/io/networked_multiplayer_peer.cpp4
-rw-r--r--core/io/networked_multiplayer_peer.h4
-rw-r--r--core/io/packed_data_container.cpp4
-rw-r--r--core/io/packed_data_container.h4
-rw-r--r--core/io/packet_peer.cpp4
-rw-r--r--core/io/packet_peer.h4
-rw-r--r--core/io/packet_peer_dtls.cpp4
-rw-r--r--core/io/packet_peer_dtls.h4
-rw-r--r--core/io/packet_peer_udp.cpp4
-rw-r--r--core/io/packet_peer_udp.h4
-rw-r--r--core/io/pck_packer.cpp6
-rw-r--r--core/io/pck_packer.h4
-rw-r--r--core/io/resource.cpp137
-rw-r--r--core/io/resource.h11
-rw-r--r--core/io/resource_format_binary.cpp83
-rw-r--r--core/io/resource_format_binary.h8
-rw-r--r--core/io/resource_importer.cpp14
-rw-r--r--core/io/resource_importer.h7
-rw-r--r--core/io/resource_loader.cpp67
-rw-r--r--core/io/resource_loader.h22
-rw-r--r--core/io/resource_saver.cpp4
-rw-r--r--core/io/resource_saver.h4
-rw-r--r--core/io/stream_peer.cpp4
-rw-r--r--core/io/stream_peer.h4
-rw-r--r--core/io/stream_peer_ssl.cpp4
-rw-r--r--core/io/stream_peer_ssl.h4
-rw-r--r--core/io/stream_peer_tcp.cpp4
-rw-r--r--core/io/stream_peer_tcp.h4
-rw-r--r--core/io/tcp_server.cpp4
-rw-r--r--core/io/tcp_server.h4
-rw-r--r--core/io/translation_loader_po.cpp8
-rw-r--r--core/io/translation_loader_po.h6
-rw-r--r--core/io/udp_server.cpp4
-rw-r--r--core/io/udp_server.h4
-rw-r--r--core/io/xml_parser.cpp70
-rw-r--r--core/io/xml_parser.h6
-rw-r--r--core/io/zip_io.cpp4
-rw-r--r--core/io/zip_io.h4
-rw-r--r--core/math/a_star.cpp10
-rw-r--r--core/math/a_star.h4
-rw-r--r--core/math/aabb.cpp4
-rw-r--r--core/math/aabb.h37
-rw-r--r--core/math/audio_frame.h7
-rw-r--r--core/math/basis.cpp8
-rw-r--r--core/math/basis.h4
-rw-r--r--core/math/camera_matrix.cpp28
-rw-r--r--core/math/camera_matrix.h7
-rw-r--r--core/math/color.cpp139
-rw-r--r--core/math/color.h32
-rw-r--r--core/math/color_names.inc2
-rw-r--r--core/math/delaunay_2d.h4
-rw-r--r--core/math/delaunay_3d.h4
-rw-r--r--core/math/disjoint_set.h4
-rw-r--r--core/math/dynamic_bvh.cpp431
-rw-r--r--core/math/dynamic_bvh.h468
-rw-r--r--core/math/expression.cpp4
-rw-r--r--core/math/expression.h4
-rw-r--r--core/math/face3.cpp4
-rw-r--r--core/math/face3.h4
-rw-r--r--core/math/geometry_2d.cpp22
-rw-r--r--core/math/geometry_2d.h15
-rw-r--r--core/math/geometry_3d.cpp27
-rw-r--r--core/math/geometry_3d.h37
-rw-r--r--core/math/math_defs.h14
-rw-r--r--core/math/math_fieldwise.cpp4
-rw-r--r--core/math/math_fieldwise.h4
-rw-r--r--core/math/math_funcs.cpp6
-rw-r--r--core/math/math_funcs.h35
-rw-r--r--core/math/octree.h22
-rw-r--r--core/math/plane.cpp4
-rw-r--r--core/math/plane.h4
-rw-r--r--core/math/quat.cpp111
-rw-r--r--core/math/quat.h23
-rw-r--r--core/math/quick_hull.cpp4
-rw-r--r--core/math/quick_hull.h4
-rw-r--r--core/math/random_number_generator.cpp4
-rw-r--r--core/math/random_number_generator.h4
-rw-r--r--core/math/random_pcg.cpp16
-rw-r--r--core/math/random_pcg.h4
-rw-r--r--core/math/rect2.cpp4
-rw-r--r--core/math/rect2.h60
-rw-r--r--core/math/transform.cpp4
-rw-r--r--core/math/transform.h12
-rw-r--r--core/math/transform_2d.cpp4
-rw-r--r--core/math/transform_2d.h4
-rw-r--r--core/math/triangle_mesh.cpp4
-rw-r--r--core/math/triangle_mesh.h4
-rw-r--r--core/math/triangulate.cpp4
-rw-r--r--core/math/triangulate.h4
-rw-r--r--core/math/vector2.cpp22
-rw-r--r--core/math/vector2.h36
-rw-r--r--core/math/vector3.cpp16
-rw-r--r--core/math/vector3.h36
-rw-r--r--core/math/vector3i.cpp4
-rw-r--r--core/math/vector3i.h4
-rw-r--r--core/object/callable_method_pointer.cpp4
-rw-r--r--core/object/callable_method_pointer.h4
-rw-r--r--core/object/class_db.cpp18
-rw-r--r--core/object/class_db.h7
-rw-r--r--core/object/message_queue.cpp4
-rw-r--r--core/object/message_queue.h4
-rw-r--r--core/object/method_bind.cpp4
-rw-r--r--core/object/method_bind.h4
-rw-r--r--core/object/object.cpp49
-rw-r--r--core/object/object.h29
-rw-r--r--core/object/object_id.h4
-rw-r--r--core/object/reference.cpp8
-rw-r--r--core/object/reference.h4
-rw-r--r--core/object/script_language.cpp16
-rw-r--r--core/object/script_language.h4
-rw-r--r--core/object/undo_redo.cpp91
-rw-r--r--core/object/undo_redo.h15
-rw-r--r--core/os/copymem.h4
-rw-r--r--core/os/dir_access.cpp6
-rw-r--r--core/os/dir_access.h4
-rw-r--r--core/os/file_access.cpp4
-rw-r--r--core/os/file_access.h4
-rw-r--r--core/os/keyboard.cpp4
-rw-r--r--core/os/keyboard.h4
-rw-r--r--core/os/main_loop.cpp28
-rw-r--r--core/os/main_loop.h16
-rw-r--r--core/os/memory.cpp30
-rw-r--r--core/os/memory.h10
-rw-r--r--core/os/midi_driver.cpp4
-rw-r--r--core/os/midi_driver.h4
-rw-r--r--core/os/mutex.cpp4
-rw-r--r--core/os/mutex.h4
-rw-r--r--core/os/os.cpp4
-rw-r--r--core/os/os.h15
-rw-r--r--core/os/pool_allocator.cpp4
-rw-r--r--core/os/pool_allocator.h4
-rw-r--r--core/os/rw_lock.cpp43
-rw-r--r--core/os/rw_lock.h88
-rw-r--r--core/os/semaphore.h4
-rw-r--r--core/os/spin_lock.h4
-rw-r--r--core/os/thread.cpp92
-rw-r--r--core/os/thread.h77
-rw-r--r--core/os/thread_dummy.cpp49
-rw-r--r--core/os/thread_dummy.h62
-rw-r--r--core/os/thread_safe.h4
-rw-r--r--core/os/threaded_array_processor.h29
-rw-r--r--core/register_core_types.cpp5
-rw-r--r--core/register_core_types.h4
-rw-r--r--core/string/compressed_translation.cpp4
-rw-r--r--core/string/compressed_translation.h4
-rw-r--r--core/string/node_path.cpp4
-rw-r--r--core/string/node_path.h4
-rw-r--r--core/string/print_string.cpp4
-rw-r--r--core/string/print_string.h4
-rw-r--r--core/string/string_buffer.h10
-rw-r--r--core/string/string_builder.cpp4
-rw-r--r--core/string/string_builder.h4
-rw-r--r--core/string/string_name.cpp4
-rw-r--r--core/string/string_name.h6
-rw-r--r--core/string/translation.cpp37
-rw-r--r--core/string/translation.h4
-rw-r--r--core/string/translation_po.cpp8
-rw-r--r--core/string/translation_po.h4
-rw-r--r--core/string/ucaps.h4
-rw-r--r--core/string/ustring.cpp273
-rw-r--r--core/string/ustring.h19
-rw-r--r--core/templates/command_queue_mt.cpp4
-rw-r--r--core/templates/command_queue_mt.h9
-rw-r--r--core/templates/cowdata.h49
-rw-r--r--core/templates/hash_map.h6
-rw-r--r--core/templates/hashfuncs.h4
-rw-r--r--core/templates/list.h6
-rw-r--r--core/templates/local_vector.h20
-rw-r--r--core/templates/lru.h4
-rw-r--r--core/templates/map.h6
-rw-r--r--core/templates/oa_hash_map.h6
-rw-r--r--core/templates/ordered_hash_map.h6
-rw-r--r--core/templates/paged_allocator.h129
-rw-r--r--core/templates/paged_array.h367
-rw-r--r--core/templates/pair.h4
-rw-r--r--core/templates/pass_func.h4
-rw-r--r--core/templates/rid.h31
-rw-r--r--core/templates/rid_owner.cpp6
-rw-r--r--core/templates/rid_owner.h112
-rw-r--r--core/templates/ring_buffer.h4
-rw-r--r--core/templates/safe_refcount.cpp161
-rw-r--r--core/templates/safe_refcount.h356
-rw-r--r--core/templates/self_list.h4
-rw-r--r--core/templates/set.h6
-rw-r--r--core/templates/simple_type.h4
-rw-r--r--core/templates/sort_array.h4
-rw-r--r--core/templates/thread_work_pool.cpp20
-rw-r--r--core/templates/thread_work_pool.h11
-rw-r--r--core/templates/vector.h10
-rw-r--r--core/templates/vmap.h10
-rw-r--r--core/templates/vset.h10
-rw-r--r--core/typedefs.h4
-rw-r--r--core/variant/array.cpp38
-rw-r--r--core/variant/array.h11
-rw-r--r--core/variant/binder_common.h7
-rw-r--r--core/variant/callable.cpp4
-rw-r--r--core/variant/callable.h4
-rw-r--r--core/variant/callable_bind.cpp4
-rw-r--r--core/variant/callable_bind.h4
-rw-r--r--core/variant/container_type_validate.h4
-rw-r--r--core/variant/dictionary.cpp12
-rw-r--r--core/variant/dictionary.h6
-rw-r--r--core/variant/method_ptrcall.h13
-rw-r--r--core/variant/type_info.h4
-rw-r--r--core/variant/typed_array.h4
-rw-r--r--core/variant/variant.cpp14
-rw-r--r--core/variant/variant.h22
-rw-r--r--core/variant/variant_call.cpp92
-rw-r--r--core/variant/variant_construct.cpp141
-rw-r--r--core/variant/variant_internal.h6
-rw-r--r--core/variant/variant_op.cpp5
-rw-r--r--core/variant/variant_parser.cpp13
-rw-r--r--core/variant/variant_parser.h4
-rw-r--r--core/variant/variant_setget.cpp257
-rw-r--r--core/variant/variant_utility.cpp18
-rw-r--r--core/version.h4
300 files changed, 4925 insertions, 2857 deletions
diff --git a/core/SCsub b/core/SCsub
index 45918fb520..21829553a7 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -38,6 +38,9 @@ with open("script_encryption_key.gen.cpp", "w") as f:
# Add required thirdparty code.
+
+thirdparty_obj = []
+
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
@@ -51,11 +54,11 @@ thirdparty_misc_sources = [
"smaz.c",
# C++ sources
"pcg.cpp",
- "triangulator.cpp",
+ "polypartition.cpp",
"clipper.cpp",
]
thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources]
-env_thirdparty.add_source_files(env.core_sources, thirdparty_misc_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources)
# Zlib library, can be unbundled
if env["builtin_zlib"]:
@@ -81,14 +84,14 @@ if env["builtin_zlib"]:
if env["target"] == "debug":
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
- env_thirdparty.add_source_files(env.core_sources, thirdparty_zlib_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
# Minizip library, could be unbundled in theory
# However, our version has some custom modifications, so it won't compile with the system one
thirdparty_minizip_dir = "#thirdparty/minizip/"
thirdparty_minizip_sources = ["ioapi.c", "unzip.c", "zip.c"]
thirdparty_minizip_sources = [thirdparty_minizip_dir + file for file in thirdparty_minizip_sources]
-env_thirdparty.add_source_files(env.core_sources, thirdparty_minizip_sources)
+env_thirdparty.add_source_files(thirdparty_obj, thirdparty_minizip_sources)
# Zstd library, can be unbundled in theory
# though we currently use some private symbols
@@ -130,10 +133,14 @@ if env["builtin_zstd"]:
# Also needed in main env includes will trigger warnings
env.Append(CPPDEFINES=["ZSTD_STATIC_LINKING_ONLY"])
- env_thirdparty.add_source_files(env.core_sources, thirdparty_zstd_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zstd_sources)
+
+env.core_sources += thirdparty_obj
+
+
+# Godot source files
-# Godot's own sources
env.add_source_files(env.core_sources, "*.cpp")
# Certificates
@@ -185,3 +192,6 @@ SConscript("error/SCsub")
# Build it all as a library
lib = env.add_library("core", env.core_sources)
env.Prepend(LIBS=[lib])
+
+# Needed to force rebuilding the core files when the thirdparty code is updated.
+env.Depends(lib, thirdparty_obj)
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 26f8cdf840..2360d66438 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/config/engine.h b/core/config/engine.h
index 0d9aa02f28..a9080e3dfd 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -50,7 +50,7 @@ private:
uint64_t frames_drawn = 0;
uint32_t _frame_delay = 0;
uint64_t _frame_ticks = 0;
- float _frame_step = 0;
+ float _process_step = 0;
int ips = 60;
float physics_jitter_fix = 0.5;
@@ -62,7 +62,7 @@ private:
bool abort_on_gpu_errors = false;
bool use_validation_layers = false;
- uint64_t _idle_frames = 0;
+ uint64_t _process_frames = 0;
bool _in_physics = false;
List<Singleton> singletons;
@@ -89,10 +89,10 @@ public:
uint64_t get_frames_drawn();
uint64_t get_physics_frames() const { return _physics_frames; }
- uint64_t get_idle_frames() const { return _idle_frames; }
+ uint64_t get_process_frames() const { return _process_frames; }
bool is_in_physics_frame() const { return _in_physics; }
- uint64_t get_idle_frame_ticks() const { return _frame_ticks; }
- float get_idle_frame_step() const { return _frame_step; }
+ 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; }
void set_time_scale(float p_scale);
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index f939fca984..02effc2001 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -32,6 +32,7 @@
#include "core/core_bind.h"
#include "core/core_string_names.h"
+#include "core/input/input_map.h"
#include "core/io/file_access_network.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
@@ -124,6 +125,11 @@ void ProjectSettings::set_restart_if_changed(const String &p_name, bool p_restar
props[p_name].restart_if_changed = p_restart;
}
+void ProjectSettings::set_as_basic(const String &p_name, bool p_basic) {
+ ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
+ props[p_name].basic = p_basic;
+}
+
void ProjectSettings::set_ignore_value_in_docs(const String &p_name, bool p_ignore) {
ERR_FAIL_COND_MSG(!props.has(p_name), "Request for nonexistent project setting: " + p_name + ".");
#ifdef DEBUG_METHODS_ENABLED
@@ -269,6 +275,10 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
vc.flags = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE;
}
+ if (v->basic) {
+ vc.flags |= PROPERTY_USAGE_EDITOR_BASIC_SETTING;
+ }
+
if (v->restart_if_changed) {
vc.flags |= PROPERTY_USAGE_RESTART_IF_CHANGED;
}
@@ -278,7 +288,7 @@ void ProjectSettings::_get_property_list(List<PropertyInfo> *p_list) const {
for (Set<_VCSort>::Element *E = vclist.front(); E; E = E->next()) {
String prop_info_name = E->get().name;
int dot = prop_info_name.find(".");
- if (dot != -1) {
+ if (dot != -1 && !custom_prop_info.has(prop_info_name)) {
prop_info_name = prop_info_name.substr(0, dot);
}
@@ -597,6 +607,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
return OK;
} else if (err != OK) {
ERR_PRINT("Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -676,7 +687,11 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- return save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ if (error == OK) {
+ last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ }
+ return error;
}
Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
@@ -894,7 +909,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
custom_features += f;
}
- if (p_path.ends_with(".godot")) {
+ if (p_path.ends_with(".godot") || p_path.ends_with("override.cfg")) {
return _save_settings_text(p_path, props, p_custom, custom_features);
} else if (p_path.ends_with(".binary")) {
return _save_settings_binary(p_path, props, p_custom, custom_features);
@@ -903,7 +918,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs) {
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed, bool p_ignore_value_in_docs, bool p_basic) {
Variant ret;
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
@@ -912,6 +927,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
+ ProjectSettings::get_singleton()->set_as_basic(p_var, p_basic);
ProjectSettings::get_singleton()->set_restart_if_changed(p_var, p_restart_if_changed);
ProjectSettings::get_singleton()->set_ignore_value_in_docs(p_var, p_ignore_value_in_docs);
return ret;
@@ -1042,29 +1058,47 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
}
+void ProjectSettings::_add_builtin_input_map() {
+ if (InputMap::get_singleton()) {
+ OrderedHashMap<String, List<Ref<InputEvent>>> builtins = InputMap::get_singleton()->get_builtins();
+
+ for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+ Array events;
+
+ // Convert list of input events into array
+ for (List<Ref<InputEvent>>::Element *I = E.get().front(); I; I = I->next()) {
+ events.push_back(I->get());
+ }
+
+ Dictionary action;
+ action["deadzone"] = Variant(0.5f);
+ action["events"] = events;
+
+ String action_name = "input/" + E.key();
+ GLOBAL_DEF(action_name, action);
+ input_presets.push_back(action_name);
+ }
+ }
+}
+
ProjectSettings::ProjectSettings() {
// Initialization of engine variables should be done in the setup() method,
// so that the values can be overridden from project.godot or project.binary.
singleton = this;
- Array events;
- Dictionary action;
- Ref<InputEventKey> key;
- Ref<InputEventJoypadButton> joyb;
-
- GLOBAL_DEF("application/config/name", "");
- GLOBAL_DEF("application/config/description", "");
+ GLOBAL_DEF_BASIC("application/config/name", "");
+ GLOBAL_DEF_BASIC("application/config/description", "");
custom_prop_info["application/config/description"] = PropertyInfo(Variant::STRING, "application/config/description", PROPERTY_HINT_MULTILINE_TEXT);
- GLOBAL_DEF("application/run/main_scene", "");
+ GLOBAL_DEF_BASIC("application/run/main_scene", "");
custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res");
GLOBAL_DEF("application/run/disable_stdout", false);
GLOBAL_DEF("application/run/disable_stderr", false);
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
- GLOBAL_DEF("audio/default_bus_layout", "res://default_bus_layout.tres");
- custom_prop_info["audio/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
+ GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
+ custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
PackedStringArray extensions = PackedStringArray();
extensions.push_back("gd");
@@ -1073,174 +1107,18 @@ ProjectSettings::ProjectSettings() {
}
extensions.push_back("shader");
- GLOBAL_DEF("editor/search_in_file_extensions", extensions);
- custom_prop_info["editor/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/search_in_file_extensions");
-
- GLOBAL_DEF("editor/script_templates_search_path", "res://script_templates");
- custom_prop_info["editor/script_templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script_templates_search_path", PROPERTY_HINT_DIR);
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_ENTER);
- events.push_back(key);
- key.instance();
- key->set_keycode(KEY_KP_ENTER);
- events.push_back(key);
- key.instance();
- key->set_keycode(KEY_SPACE);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_A);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_accept", action);
- input_presets.push_back("input/ui_accept");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_SPACE);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_Y);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_select", action);
- input_presets.push_back("input/ui_select");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_ESCAPE);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_B);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_cancel", action);
- input_presets.push_back("input/ui_cancel");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_TAB);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_focus_next", action);
- input_presets.push_back("input/ui_focus_next");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_TAB);
- key->set_shift(true);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_focus_prev", action);
- input_presets.push_back("input/ui_focus_prev");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_LEFT);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_LEFT);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_left", action);
- input_presets.push_back("input/ui_left");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_RIGHT);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_RIGHT);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_right", action);
- input_presets.push_back("input/ui_right");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_UP);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_UP);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_up", action);
- input_presets.push_back("input/ui_up");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_DOWN);
- events.push_back(key);
- joyb.instance();
- joyb->set_button_index(JOY_BUTTON_DPAD_DOWN);
- events.push_back(joyb);
- action["events"] = events;
- GLOBAL_DEF("input/ui_down", action);
- input_presets.push_back("input/ui_down");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_PAGEUP);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_page_up", action);
- input_presets.push_back("input/ui_page_up");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_PAGEDOWN);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_page_down", action);
- input_presets.push_back("input/ui_page_down");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_HOME);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_home", action);
- input_presets.push_back("input/ui_home");
-
- action = Dictionary();
- action["deadzone"] = Variant(0.5f);
- events = Array();
- key.instance();
- key->set_keycode(KEY_END);
- events.push_back(key);
- action["events"] = events;
- GLOBAL_DEF("input/ui_end", action);
- input_presets.push_back("input/ui_end");
+ GLOBAL_DEF("editor/script/search_in_file_extensions", extensions);
+ custom_prop_info["editor/script/search_in_file_extensions"] = PropertyInfo(Variant::PACKED_STRING_ARRAY, "editor/script/search_in_file_extensions");
+
+ GLOBAL_DEF("editor/script/templates_search_path", "res://script_templates");
+ custom_prop_info["editor/script/templates_search_path"] = PropertyInfo(Variant::STRING, "editor/script/templates_search_path", PROPERTY_HINT_DIR);
+
+ _add_builtin_input_map();
custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor");
- custom_prop_info["rendering/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
- custom_prop_info["physics/2d/thread_model"] = PropertyInfo(Variant::INT, "physics/2d/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
- custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
+ custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded");
+ GLOBAL_DEF("physics/2d/run_on_thread", false);
+ GLOBAL_DEF("physics/3d/run_on_thread", false);
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 5a16248c76..ed8fb19fa0 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -58,6 +58,7 @@ protected:
struct VariantContainer {
int order = 0;
bool persist = false;
+ bool basic = false;
Variant variant;
Variant initial;
bool hide_from_editor = false;
@@ -78,6 +79,8 @@ protected:
int last_order = NO_BUILTIN_ORDER_BASE;
int last_builtin_order = 0;
+ uint64_t last_save_time = 0;
+
Map<StringName, VariantContainer> props;
String resource_path;
Map<StringName, PropertyInfo> custom_prop_info;
@@ -113,6 +116,8 @@ protected:
Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
+ void _add_builtin_input_map();
+
protected:
static void _bind_methods();
@@ -127,6 +132,7 @@ public:
String globalize_path(const String &p_path) const;
void set_initial_value(const String &p_name, const Variant &p_value);
+ void set_as_basic(const String &p_name, bool p_basic);
void set_restart_if_changed(const String &p_name, bool p_restart);
void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
bool get_ignore_value_in_docs(const String &p_name) const;
@@ -150,6 +156,7 @@ public:
Error save();
void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info);
const Map<StringName, PropertyInfo> &get_custom_property_info() const;
+ uint64_t get_last_saved_time() { return last_save_time; }
Vector<String> get_optimizer_presets() const;
@@ -172,11 +179,16 @@ public:
};
//not a macro any longer
-Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false);
+Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restart_if_changed = false, bool p_ignore_value_in_docs = false, bool p_basic = false);
#define GLOBAL_DEF(m_var, m_value) _GLOBAL_DEF(m_var, m_value)
#define GLOBAL_DEF_RST(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true)
#define GLOBAL_DEF_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true)
#define GLOBAL_DEF_RST_NOVAL(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true)
#define GLOBAL_GET(m_var) ProjectSettings::get_singleton()->get(m_var)
+#define GLOBAL_DEF_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, false, true)
+#define GLOBAL_DEF_RST_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, false, true)
+#define GLOBAL_DEF_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, false, true, true)
+#define GLOBAL_DEF_RST_NOVAL_BASIC(m_var, m_value) _GLOBAL_DEF(m_var, m_value, true, true, true)
+
#endif // PROJECT_SETTINGS_H
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 259d899d39..e7a77384da 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -86,9 +86,9 @@ RES _ResourceLoader::load_threaded_get(const String &p_path) {
return res;
}
-RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache) {
+RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, CacheMode p_cache_mode) {
Error err = OK;
- RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache, &err);
+ RES ret = ResourceLoader::load(p_path, p_type_hint, ResourceFormatLoader::CacheMode(p_cache_mode), &err);
ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'.");
return ret;
@@ -135,7 +135,7 @@ void _ResourceLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("load_threaded_get_status", "path", "progress"), &_ResourceLoader::load_threaded_get_status, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("load_threaded_get", "path"), &_ResourceLoader::load_threaded_get);
- ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "no_cache"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &_ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type);
ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies);
@@ -146,6 +146,10 @@ void _ResourceLoader::_bind_methods() {
BIND_ENUM_CONSTANT(THREAD_LOAD_IN_PROGRESS);
BIND_ENUM_CONSTANT(THREAD_LOAD_FAILED);
BIND_ENUM_CONSTANT(THREAD_LOAD_LOADED);
+
+ BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REUSE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
}
////// _ResourceSaver //////
@@ -228,24 +232,32 @@ Error _OS::shell_open(String p_uri) {
return OS::get_singleton()->shell_open(p_uri);
}
-int _OS::execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking, Array p_output, bool p_read_stderr) {
- OS::ProcessID pid = -2;
- int exitcode = 0;
+int _OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr) {
List<String> args;
for (int i = 0; i < p_arguments.size(); i++) {
args.push_back(p_arguments[i]);
}
String pipe;
- Error err = OS::get_singleton()->execute(p_path, args, p_blocking, &pid, &pipe, &exitcode, p_read_stderr);
- p_output.clear();
- p_output.push_back(pipe);
+ int exitcode = 0;
+ Error err = OS::get_singleton()->execute(p_path, args, &pipe, &exitcode, p_read_stderr);
+ r_output.push_back(pipe);
if (err != OK) {
return -1;
- } else if (p_blocking) {
- return exitcode;
- } else {
- return pid;
}
+ return exitcode;
+}
+
+int _OS::create_process(const String &p_path, const Vector<String> &p_arguments) {
+ List<String> args;
+ for (int i = 0; i < p_arguments.size(); i++) {
+ args.push_back(p_arguments[i]);
+ }
+ OS::ProcessID pid = 0;
+ Error err = OS::get_singleton()->create_process(p_path, args, &pid);
+ if (err != OK) {
+ return -1;
+ }
+ return pid;
}
Error _OS::kill(int p_pid) {
@@ -264,6 +276,10 @@ String _OS::get_environment(const String &p_var) const {
return OS::get_singleton()->get_environment(p_var);
}
+bool _OS::set_environment(const String &p_var, const String &p_value) const {
+ return OS::get_singleton()->set_environment(p_var, p_value);
+}
+
String _OS::get_name() const {
return OS::get_singleton()->get_name();
}
@@ -290,6 +306,10 @@ Error _OS::set_thread_name(const String &p_name) {
return Thread::set_name(p_name);
}
+Thread::ID _OS::get_thread_caller_id() const {
+ return Thread::get_caller_id();
+};
+
bool _OS::has_feature(const String &p_feature) const {
return OS::get_singleton()->has_feature(p_feature);
}
@@ -302,18 +322,6 @@ uint64_t _OS::get_static_memory_peak_usage() const {
return OS::get_singleton()->get_static_memory_peak_usage();
}
-int _OS::get_exit_code() const {
- return OS::get_singleton()->get_exit_code();
-}
-
-void _OS::set_exit_code(int p_code) {
- if (p_code < 0 || p_code > 125) {
- WARN_PRINT("For portability reasons, the exit code should be set between 0 and 125 (inclusive).");
- }
-
- OS::get_singleton()->set_exit_code(p_code);
-}
-
/**
* Get current datetime with consideration for utc and
* dst
@@ -503,11 +511,19 @@ double _OS::get_unix_time() const {
return OS::get_singleton()->get_unix_time();
}
-void _OS::delay_usec(uint32_t p_usec) const {
+/** This method uses a signed argument for better error reporting as it's used from the scripting API. */
+void _OS::delay_usec(int p_usec) const {
+ ERR_FAIL_COND_MSG(
+ p_usec < 0,
+ vformat("Can't sleep for %d microseconds. The delay provided must be greater than or equal to 0 microseconds.", p_usec));
OS::get_singleton()->delay_usec(p_usec);
}
-void _OS::delay_msec(uint32_t p_msec) const {
+/** This method uses a signed argument for better error reporting as it's used from the scripting API. */
+void _OS::delay_msec(int p_msec) const {
+ ERR_FAIL_COND_MSG(
+ p_msec < 0,
+ vformat("Can't sleep for %d milliseconds. The delay provided must be greater than or equal to 0 milliseconds.", p_msec));
OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000);
}
@@ -550,7 +566,7 @@ struct _OSCoreBindImg {
void _OS::print_all_textures_by_size() {
List<_OSCoreBindImg> imgs;
- int total = 0;
+ uint64_t total = 0;
{
List<Ref<Resource>> rsrc;
ResourceCache::get_cached_resources(&rsrc);
@@ -587,10 +603,7 @@ void _OS::print_resources_by_type(const Vector<String> &p_types) {
List<Ref<Resource>> resources;
ResourceCache::get_cached_resources(&resources);
- List<Ref<Resource>> rsrc;
- ResourceCache::get_cached_resources(&rsrc);
-
- for (List<Ref<Resource>>::Element *E = rsrc.front(); E; E = E->next()) {
+ for (List<Ref<Resource>>::Element *E = resources.front(); E; E = E->next()) {
Ref<Resource> r = E->get();
bool found = false;
@@ -668,22 +681,6 @@ String _OS::get_unique_id() const {
return OS::get_singleton()->get_unique_id();
}
-int _OS::get_tablet_driver_count() const {
- return OS::get_singleton()->get_tablet_driver_count();
-}
-
-String _OS::get_tablet_driver_name(int p_driver) const {
- return OS::get_singleton()->get_tablet_driver_name(p_driver);
-}
-
-String _OS::get_current_tablet_driver() const {
- return OS::get_singleton()->get_current_tablet_driver();
-}
-
-void _OS::set_current_tablet_driver(const String &p_driver) {
- OS::get_singleton()->set_current_tablet_driver(p_driver);
-}
-
_OS *_OS::singleton = nullptr;
void _OS::_bind_methods() {
@@ -700,13 +697,15 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_processor_count"), &_OS::get_processor_count);
ClassDB::bind_method(D_METHOD("get_executable_path"), &_OS::get_executable_path);
- ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "blocking", "output", "read_stderr"), &_OS::execute, DEFVAL(true), DEFVAL(Array()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr"), &_OS::execute, DEFVAL(Array()), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("create_process", "path", "arguments"), &_OS::create_process);
ClassDB::bind_method(D_METHOD("kill", "pid"), &_OS::kill);
ClassDB::bind_method(D_METHOD("shell_open", "uri"), &_OS::shell_open);
ClassDB::bind_method(D_METHOD("get_process_id"), &_OS::get_process_id);
- ClassDB::bind_method(D_METHOD("get_environment", "environment"), &_OS::get_environment);
- ClassDB::bind_method(D_METHOD("has_environment", "environment"), &_OS::has_environment);
+ ClassDB::bind_method(D_METHOD("get_environment", "variable"), &_OS::get_environment);
+ ClassDB::bind_method(D_METHOD("set_environment", "variable", "value"), &_OS::set_environment);
+ ClassDB::bind_method(D_METHOD("has_environment", "variable"), &_OS::has_environment);
ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name);
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args);
@@ -719,9 +718,6 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time);
ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime);
- ClassDB::bind_method(D_METHOD("get_exit_code"), &_OS::get_exit_code);
- ClassDB::bind_method(D_METHOD("set_exit_code", "code"), &_OS::set_exit_code);
-
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec);
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec);
ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec);
@@ -758,6 +754,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_file_access_save_and_swap", "enabled"), &_OS::set_use_file_access_save_and_swap);
ClassDB::bind_method(D_METHOD("set_thread_name", "name"), &_OS::set_thread_name);
+ ClassDB::bind_method(D_METHOD("get_thread_caller_id"), &_OS::get_thread_caller_id);
ClassDB::bind_method(D_METHOD("has_feature", "tag_name"), &_OS::has_feature);
@@ -765,19 +762,11 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("request_permissions"), &_OS::request_permissions);
ClassDB::bind_method(D_METHOD("get_granted_permissions"), &_OS::get_granted_permissions);
- ClassDB::bind_method(D_METHOD("get_tablet_driver_count"), &_OS::get_tablet_driver_count);
- ClassDB::bind_method(D_METHOD("get_tablet_driver_name", "idx"), &_OS::get_tablet_driver_name);
- ClassDB::bind_method(D_METHOD("get_current_tablet_driver"), &_OS::get_current_tablet_driver);
- ClassDB::bind_method(D_METHOD("set_current_tablet_driver", "name"), &_OS::set_current_tablet_driver);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "exit_code"), "set_exit_code", "get_exit_code");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "low_processor_usage_mode"), "set_low_processor_usage_mode", "is_in_low_processor_usage_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "low_processor_usage_mode_sleep_usec"), "set_low_processor_usage_mode_sleep_usec", "get_low_processor_usage_mode_sleep_usec");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "tablet_driver"), "set_current_tablet_driver", "get_current_tablet_driver");
// Those default values need to be specified for the docs generator,
// to avoid using values from the documentation writer's own OS instance.
- ADD_PROPERTY_DEFAULT("tablet_driver", "");
ADD_PROPERTY_DEFAULT("exit_code", 0);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
@@ -1239,6 +1228,11 @@ Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
return err;
}
+void _File::flush() {
+ ERR_FAIL_COND_MSG(!f, "File must be opened before flushing.");
+ f->flush();
+}
+
void _File::close() {
if (f) {
memdelete(f);
@@ -1532,6 +1526,7 @@ void _File::_bind_methods() {
ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &_File::open_compressed, DEFVAL(0));
ClassDB::bind_method(D_METHOD("open", "path", "flags"), &_File::open);
+ ClassDB::bind_method(D_METHOD("flush"), &_File::flush);
ClassDB::bind_method(D_METHOD("close"), &_File::close);
ClassDB::bind_method(D_METHOD("get_path"), &_File::get_path);
ClassDB::bind_method(D_METHOD("get_path_absolute"), &_File::get_path_absolute);
@@ -1969,7 +1964,7 @@ void _Thread::_start_func(void *ud) {
}
Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
- ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "Thread already started.");
+ ERR_FAIL_COND_V_MSG(active.is_set(), ERR_ALREADY_IN_USE, "Thread already started.");
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
@@ -1978,49 +1973,33 @@ Error _Thread::start(Object *p_instance, const StringName &p_method, const Varia
target_method = p_method;
target_instance = p_instance;
userdata = p_userdata;
- active = true;
+ active.set();
Ref<_Thread> *ud = memnew(Ref<_Thread>(this));
Thread::Settings s;
s.priority = (Thread::Priority)p_priority;
- thread = Thread::create(_start_func, ud, s);
- if (!thread) {
- active = false;
- target_method = StringName();
- target_instance = nullptr;
- userdata = Variant();
- return ERR_CANT_CREATE;
- }
+ thread.start(_start_func, ud, s);
return OK;
}
String _Thread::get_id() const {
- if (!thread) {
- return String();
- }
-
- return itos(thread->get_id());
+ return itos(thread.get_id());
}
bool _Thread::is_active() const {
- return active;
+ return active.is_set();
}
Variant _Thread::wait_to_finish() {
- ERR_FAIL_COND_V_MSG(!thread, Variant(), "Thread must exist to wait for its completion.");
- ERR_FAIL_COND_V_MSG(!active, Variant(), "Thread must be active to wait for its completion.");
- Thread::wait_to_finish(thread);
+ ERR_FAIL_COND_V_MSG(!active.is_set(), Variant(), "Thread must be active to wait for its completion.");
+ thread.wait_to_finish();
Variant r = ret;
- active = false;
+ active.clear();
target_method = StringName();
target_instance = nullptr;
userdata = Variant();
- if (thread) {
- memdelete(thread);
- }
- thread = nullptr;
return r;
}
@@ -2036,10 +2015,6 @@ void _Thread::_bind_methods() {
BIND_ENUM_CONSTANT(PRIORITY_HIGH);
}
-_Thread::~_Thread() {
- ERR_FAIL_COND_MSG(active, "Reference to a Thread object was lost while the thread is still running...");
-}
-
////// _ClassDB //////
PackedStringArray _ClassDB::get_class_list() const {
@@ -2278,8 +2253,8 @@ uint64_t _Engine::get_physics_frames() const {
return Engine::get_singleton()->get_physics_frames();
}
-uint64_t _Engine::get_idle_frames() const {
- return Engine::get_singleton()->get_idle_frames();
+uint64_t _Engine::get_process_frames() const {
+ return Engine::get_singleton()->get_process_frames();
}
void _Engine::set_time_scale(float p_scale) {
@@ -2358,7 +2333,7 @@ void _Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_frames_drawn"), &_Engine::get_frames_drawn);
ClassDB::bind_method(D_METHOD("get_frames_per_second"), &_Engine::get_frames_per_second);
ClassDB::bind_method(D_METHOD("get_physics_frames"), &_Engine::get_physics_frames);
- ClassDB::bind_method(D_METHOD("get_idle_frames"), &_Engine::get_idle_frames);
+ ClassDB::bind_method(D_METHOD("get_process_frames"), &_Engine::get_process_frames);
ClassDB::bind_method(D_METHOD("get_main_loop"), &_Engine::get_main_loop);
diff --git a/core/core_bind.h b/core/core_bind.h
index f3a77a4fa6..3920116ca4 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,6 +40,7 @@
#include "core/os/os.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
class _ResourceLoader : public Object {
GDCLASS(_ResourceLoader, Object);
@@ -56,13 +57,19 @@ public:
THREAD_LOAD_LOADED
};
+ enum CacheMode {
+ CACHE_MODE_IGNORE, //resource and subresources do not use path cache, no path is set into resource.
+ CACHE_MODE_REUSE, //resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available
+ CACHE_MODE_REPLACE, //resource and and subresource use path cache, but replace existing loaded resources when available with information from disk
+ };
+
static _ResourceLoader *get_singleton() { return singleton; }
Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false);
ThreadLoadStatus load_threaded_get_status(const String &p_path, Array r_progress = Array());
RES load_threaded_get(const String &p_path);
- RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false);
+ RES load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
Vector<String> get_recognized_extensions_for_type(const String &p_type);
void set_abort_on_missing_resources(bool p_abort);
PackedStringArray get_dependencies(const String &p_path);
@@ -73,6 +80,7 @@ public:
};
VARIANT_ENUM_CAST(_ResourceLoader::ThreadLoadStatus);
+VARIANT_ENUM_CAST(_ResourceLoader::CacheMode);
class _ResourceSaver : public Object {
GDCLASS(_ResourceSaver, Object);
@@ -155,8 +163,8 @@ public:
int get_low_processor_usage_mode_sleep_usec() const;
String get_executable_path() const;
- int execute(const String &p_path, const Vector<String> &p_arguments, bool p_blocking = true, Array p_output = Array(), bool p_read_stderr = false);
-
+ int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false);
+ int create_process(const String &p_path, const Vector<String> &p_arguments);
Error kill(int p_pid);
Error shell_open(String p_uri);
@@ -164,6 +172,7 @@ public:
bool has_environment(const String &p_var) const;
String get_environment(const String &p_var) const;
+ bool set_environment(const String &p_var, const String &p_value) const;
String get_name() const;
Vector<String> get_cmdline_args();
@@ -190,8 +199,6 @@ public:
void set_use_file_access_save_and_swap(bool p_enable);
- int get_exit_code() const;
- void set_exit_code(int p_code);
Dictionary get_date(bool utc) const;
Dictionary get_time(bool utc) const;
Dictionary get_datetime(bool utc) const;
@@ -203,8 +210,8 @@ public:
uint64_t get_static_memory_usage() const;
uint64_t get_static_memory_peak_usage() const;
- void delay_usec(uint32_t p_usec) const;
- void delay_msec(uint32_t p_msec) const;
+ void delay_usec(int p_usec) const;
+ void delay_msec(int p_msec) const;
uint32_t get_ticks_msec() const;
uint64_t get_ticks_usec() const;
@@ -232,6 +239,7 @@ public:
String get_user_data_dir() const;
Error set_thread_name(const String &p_name);
+ Thread::ID get_thread_caller_id() const;
bool has_feature(const String &p_feature) const;
@@ -239,11 +247,6 @@ public:
bool request_permissions();
Vector<String> get_granted_permissions() const;
- int get_tablet_driver_count() const;
- String get_tablet_driver_name(int p_driver) const;
- String get_current_tablet_driver() const;
- void set_current_tablet_driver(const String &p_driver);
-
static _OS *get_singleton() { return singleton; }
_OS() { singleton = this; }
@@ -378,6 +381,7 @@ public:
Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
Error open(const String &p_path, ModeFlags p_mode_flags); // open a file.
+ void flush(); // Flush a file (write its buffer to disk).
void close(); // Close a file.
bool is_open() const; // True when file is open.
@@ -550,10 +554,10 @@ class _Thread : public Reference {
protected:
Variant ret;
Variant userdata;
- volatile bool active = false;
+ SafeFlag active;
Object *target_instance = nullptr;
StringName target_method;
- Thread *thread = nullptr;
+ Thread thread;
static void _bind_methods();
static void _start_func(void *ud);
@@ -569,9 +573,6 @@ public:
String get_id() const;
bool is_active() const;
Variant wait_to_finish();
-
- _Thread() {}
- ~_Thread();
};
VARIANT_ENUM_CAST(_Thread::Priority);
@@ -635,7 +636,7 @@ public:
float get_frames_per_second() const;
uint64_t get_physics_frames() const;
- uint64_t get_idle_frames() const;
+ uint64_t get_process_frames() const;
int get_frames_drawn();
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 02055012ad..f9edff1899 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -112,10 +112,10 @@ VARIANT_ENUM_CAST(JoyAxisList);
VARIANT_ENUM_CAST(MidiMessageList);
void register_global_constants() {
- BIND_CORE_ENUM_CONSTANT(MARGIN_LEFT);
- BIND_CORE_ENUM_CONSTANT(MARGIN_TOP);
- BIND_CORE_ENUM_CONSTANT(MARGIN_RIGHT);
- BIND_CORE_ENUM_CONSTANT(MARGIN_BOTTOM);
+ BIND_CORE_ENUM_CONSTANT(SIDE_LEFT);
+ BIND_CORE_ENUM_CONSTANT(SIDE_TOP);
+ BIND_CORE_ENUM_CONSTANT(SIDE_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(SIDE_BOTTOM);
BIND_CORE_ENUM_CONSTANT(CORNER_TOP_LEFT);
BIND_CORE_ENUM_CONSTANT(CORNER_TOP_RIGHT);
@@ -125,6 +125,9 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(VERTICAL);
BIND_CORE_ENUM_CONSTANT(HORIZONTAL);
+ BIND_CORE_ENUM_CONSTANT(CLOCKWISE);
+ BIND_CORE_ENUM_CONSTANT(COUNTERCLOCKWISE);
+
BIND_CORE_ENUM_CONSTANT(HALIGN_LEFT);
BIND_CORE_ENUM_CONSTANT(HALIGN_CENTER);
BIND_CORE_ENUM_CONSTANT(HALIGN_RIGHT);
@@ -426,6 +429,12 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_DOWN);
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_LEFT);
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_DPAD_RIGHT);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_MISC1);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_PADDLE1);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_PADDLE2);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_PADDLE3);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_PADDLE4);
+ BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_TOUCHPAD);
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_SDL_MAX);
BIND_CORE_ENUM_CONSTANT(JOY_BUTTON_MAX);
@@ -525,6 +534,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_COLOR_NO_ALPHA);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSY);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_STORAGE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR);
diff --git a/core/core_constants.h b/core/core_constants.h
index 6cddd9daec..deaf9ec60f 100644
--- a/core/core_constants.h
+++ b/core/core_constants.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index 6f86f107e6..ff8569e45d 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -76,5 +76,6 @@ CoreStringNames::CoreStringNames() :
bind(StaticCString::create("bind")),
unbind(StaticCString::create("unbind")),
emit(StaticCString::create("emit")),
- notification(StaticCString::create("notification")) {
+ notification(StaticCString::create("notification")),
+ property_list_changed(StaticCString::create("property_list_changed")) {
}
diff --git a/core/core_string_names.h b/core/core_string_names.h
index c0bdc33d28..abe751372e 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -96,6 +96,7 @@ public:
StringName unbind;
StringName emit;
StringName notification;
+ StringName property_list_changed;
};
#endif // CORE_STRING_NAMES_H
diff --git a/core/crypto/SCsub b/core/crypto/SCsub
index da4a9c9381..4f3104d84b 100644
--- a/core/crypto/SCsub
+++ b/core/crypto/SCsub
@@ -6,6 +6,7 @@ env_crypto = env.Clone()
is_builtin = env["builtin_mbedtls"]
has_module = env["module_mbedtls_enabled"]
+thirdparty_obj = []
if is_builtin or not has_module:
# Use our headers for builtin or if the module is not going to be compiled.
@@ -35,6 +36,16 @@ if not has_module:
"godot_core_mbedtls_platform.c",
]
thirdparty_mbedtls_sources = [thirdparty_mbedtls_dir + file for file in thirdparty_mbedtls_sources]
- env_thirdparty.add_source_files(env.core_sources, thirdparty_mbedtls_sources)
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_mbedtls_sources)
+ env.core_sources += thirdparty_obj
-env_crypto.add_source_files(env.core_sources, "*.cpp")
+
+# Godot source files
+
+core_obj = []
+
+env_crypto.add_source_files(core_obj, "*.cpp")
+env.core_sources += core_obj
+
+# Needed to force rebuilding the core files when the thirdparty library is updated.
+env.Depends(core_obj, thirdparty_obj)
diff --git a/core/crypto/aes_context.cpp b/core/crypto/aes_context.cpp
index 608f3c912c..b387aeb27d 100644
--- a/core/crypto/aes_context.cpp
+++ b/core/crypto/aes_context.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h
index 557bde1f04..cc00b18fd2 100644
--- a/core/crypto/aes_context.h
+++ b/core/crypto/aes_context.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/crypto/crypto.cpp b/core/crypto/crypto.cpp
index 33ba0ba704..f43f3e3290 100644
--- a/core/crypto/crypto.cpp
+++ b/core/crypto/crypto.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -141,7 +141,7 @@ void Crypto::_bind_methods() {
/// Resource loader/saver
-RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderCrypto::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
String el = p_path.get_extension().to_lower();
if (el == "crt") {
X509Certificate *cert = X509Certificate::create();
diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h
index 5cacddaea0..9438fcfea5 100644
--- a/core/crypto/crypto.h
+++ b/core/crypto/crypto.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -116,7 +116,7 @@ public:
class ResourceFormatLoaderCrypto : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/crypto/crypto_core.cpp b/core/crypto/crypto_core.cpp
index 117e47d538..f90092056e 100644
--- a/core/crypto/crypto_core.cpp
+++ b/core/crypto/crypto_core.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h
index c2ec6febe3..27b380e838 100644
--- a/core/crypto/crypto_core.h
+++ b/core/crypto/crypto_core.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/crypto/hashing_context.cpp b/core/crypto/hashing_context.cpp
index fb0dadfbab..070d2d4dd7 100644
--- a/core/crypto/hashing_context.cpp
+++ b/core/crypto/hashing_context.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/crypto/hashing_context.h b/core/crypto/hashing_context.h
index 7cd55ba267..892a48a4e8 100644
--- a/core/crypto/hashing_context.h
+++ b/core/crypto/hashing_context.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/debugger/debugger_marshalls.cpp b/core/debugger/debugger_marshalls.cpp
index 03de832b5e..26f82c2658 100644
--- a/core/debugger/debugger_marshalls.cpp
+++ b/core/debugger/debugger_marshalls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/debugger/debugger_marshalls.h b/core/debugger/debugger_marshalls.h
index 0c13790d60..3e8c34d84b 100644
--- a/core/debugger/debugger_marshalls.h
+++ b/core/debugger/debugger_marshalls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/debugger/engine_debugger.cpp b/core/debugger/engine_debugger.cpp
index 4bf31aa55f..895b8c23a9 100644
--- a/core/debugger/engine_debugger.cpp
+++ b/core/debugger/engine_debugger.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -117,9 +117,9 @@ void EngineDebugger::line_poll() {
poll_every++;
}
-void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_idle_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, float p_physics_frame_time) {
frame_time = USEC_TO_SEC(p_frame_ticks);
- idle_time = USEC_TO_SEC(p_idle_ticks);
+ process_time = USEC_TO_SEC(p_process_ticks);
physics_time = USEC_TO_SEC(p_physics_ticks);
physics_frame_time = p_physics_frame_time;
// Notify tick to running profilers
@@ -128,14 +128,14 @@ void EngineDebugger::iteration(uint64_t p_frame_ticks, uint64_t p_idle_ticks, ui
if (!p.active || !p.tick) {
continue;
}
- p.tick(p.data, frame_time, idle_time, physics_time, physics_frame_time);
+ p.tick(p.data, frame_time, process_time, physics_time, physics_frame_time);
}
singleton->poll_events(true);
}
void EngineDebugger::initialize(const String &p_uri, bool p_skip_breakpoints, Vector<String> p_breakpoints) {
register_uri_handler("tcp://", RemoteDebuggerPeerTCP::create); // TCP is the default protocol. Platforms/modules can add more.
- if (p_uri.empty()) {
+ if (p_uri.is_empty()) {
return;
}
if (p_uri == "local://") {
diff --git a/core/debugger/engine_debugger.h b/core/debugger/engine_debugger.h
index 10f04bf97a..c6daea6e2f 100644
--- a/core/debugger/engine_debugger.h
+++ b/core/debugger/engine_debugger.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -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_idle_time, float p_physics_time, float p_physics_frame_time);
+ 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 (*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);
@@ -86,7 +86,7 @@ public:
private:
float frame_time = 0.0;
- float idle_time = 0.0;
+ float process_time = 0.0;
float physics_time = 0.0;
float physics_frame_time = 0.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_idle_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, float 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 876be79418..1dd7e268a5 100644
--- a/core/debugger/local_debugger.cpp
+++ b/core/debugger/local_debugger.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -117,7 +117,7 @@ struct LocalDebugger::ScriptsProfiler {
void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
ScriptLanguage *script_lang = script_debugger->get_break_language();
- if (!target_function.empty()) {
+ if (!target_function.is_empty()) {
String current_function = script_lang->debug_get_stack_level_function(0);
if (current_function != target_function) {
script_debugger->set_depth(0);
@@ -259,7 +259,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
String source = breakpoint.first;
int linenr = breakpoint.second;
- if (source.empty()) {
+ if (source.is_empty()) {
continue;
}
@@ -285,7 +285,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
String source = breakpoint.first;
int linenr = breakpoint.second;
- if (source.empty()) {
+ if (source.is_empty()) {
continue;
}
@@ -323,7 +323,7 @@ void LocalDebugger::print_variables(const List<String> &names, const List<Varian
for (const List<String>::Element *E = names.front(); E; E = E->next()) {
value = String(V->get());
- if (variable_prefix.empty()) {
+ if (variable_prefix.is_empty()) {
print_line(E->get() + ": " + String(V->get()));
} else {
print_line(E->get() + ":");
@@ -359,7 +359,7 @@ void LocalDebugger::send_message(const String &p_message, const Array &p_args) {
}
void LocalDebugger::send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type) {
- print_line("ERROR: '" + (p_descr.empty() ? p_err : p_descr) + "'");
+ print_line("ERROR: '" + (p_descr.is_empty() ? p_err : p_descr) + "'");
}
LocalDebugger::LocalDebugger() {
diff --git a/core/debugger/local_debugger.h b/core/debugger/local_debugger.h
index dbdeec173b..e793b2a859 100644
--- a/core/debugger/local_debugger.h
+++ b/core/debugger/local_debugger.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index ff89517497..bdbb7766fa 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -76,6 +76,7 @@ public:
NetworkProfiler() {}
int bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) {
+ ERR_FAIL_COND_V(p_buffer.size() == 0, 0);
int total_bandwidth = 0;
uint32_t timestamp = OS::get_singleton()->get_ticks_msec();
@@ -317,7 +318,7 @@ struct RemoteDebugger::ServersProfiler {
void _send_frame_data(bool p_final) {
DebuggerMarshalls::ServersProfilerFrame frame;
- frame.frame_number = Engine::get_singleton()->get_idle_frames();
+ frame.frame_number = Engine::get_singleton()->get_process_frames();
frame.frame_time = frame_time;
frame.idle_time = idle_time;
frame.physics_time = physics_time;
@@ -553,7 +554,7 @@ void RemoteDebugger::flush_output() {
for (int i = 0; i < output_strings.size(); i++) {
const OutputString &output_string = output_strings[i];
if (output_string.type == MESSAGE_TYPE_ERROR) {
- if (!joined_log_strings.empty()) {
+ if (!joined_log_strings.is_empty()) {
strings.push_back(String("\n").join(joined_log_strings));
types.push_back(MESSAGE_TYPE_LOG);
joined_log_strings.clear();
@@ -565,7 +566,7 @@ void RemoteDebugger::flush_output() {
}
}
- if (!joined_log_strings.empty()) {
+ if (!joined_log_strings.is_empty()) {
strings.push_back(String("\n").join(joined_log_strings));
types.push_back(MESSAGE_TYPE_LOG);
}
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index 37cc8af2a5..28e670747e 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 338c637014..857e3af268 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -65,12 +65,8 @@ int RemoteDebuggerPeerTCP::get_max_message_size() const {
}
void RemoteDebuggerPeerTCP::close() {
- if (thread) {
- running = false;
- Thread::wait_to_finish(thread);
- memdelete(thread);
- thread = nullptr;
- }
+ running = false;
+ thread.wait_to_finish();
tcp_client->disconnect_from_host();
out_buf.resize(0);
in_buf.resize(0);
@@ -85,7 +81,7 @@ RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) {
connected = true;
#ifndef NO_THREADS
running = true;
- thread = Thread::create(_thread_func, this);
+ thread.start(_thread_func, this);
#endif
} else {
tcp_client.instance();
@@ -188,7 +184,7 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
connected = true;
#ifndef NO_THREADS
running = true;
- thread = Thread::create(_thread_func, this);
+ thread.start(_thread_func, this);
#endif
return OK;
}
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index 79b88f5549..652e2d9d20 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -58,7 +58,7 @@ class RemoteDebuggerPeerTCP : public RemoteDebuggerPeer {
private:
Ref<StreamPeerTCP> tcp_client;
Mutex mutex;
- Thread *thread = nullptr;
+ Thread thread;
List<Array> in_queue;
List<Array> out_queue;
int out_left = 0;
diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp
index 0cd3238efb..6d1e4ed101 100644
--- a/core/debugger/script_debugger.cpp
+++ b/core/debugger/script_debugger.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index 7f2f2becc2..9f034a5e5d 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/doc_data.cpp b/core/doc_data.cpp
index d84ac6d05b..45450bf97a 100644
--- a/core/doc_data.cpp
+++ b/core/doc_data.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/doc_data.h b/core/doc_data.h
index 65b57d1381..46ab697768 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/error/error_list.h b/core/error/error_list.h
index a0218cf045..f032f44c1f 100644
--- a/core/error/error_list.h
+++ b/core/error/error_list.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp
index 80879dd25d..272dda97d8 100644
--- a/core/error/error_macros.cpp
+++ b/core/error/error_macros.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 6353961b04..f909a67d55 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -33,6 +33,8 @@
#include "core/typedefs.h"
+#include "core/templates/safe_refcount.h"
+
class String;
enum ErrorHandlerType {
@@ -577,10 +579,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
*/
#define WARN_DEPRECATED \
if (true) { \
- static volatile bool warning_shown = false; \
- if (!warning_shown) { \
+ static SafeFlag warning_shown; \
+ if (!warning_shown.is_set()) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", ERR_HANDLER_WARNING); \
- warning_shown = true; \
+ warning_shown.set(); \
} \
} else \
((void)0)
@@ -590,10 +592,10 @@ void _err_print_index_error(const char *p_function, const char *p_file, int p_li
*/
#define WARN_DEPRECATED_MSG(m_msg) \
if (true) { \
- static volatile bool warning_shown = false; \
- if (!warning_shown) { \
+ static SafeFlag warning_shown; \
+ if (!warning_shown.is_set()) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future.", DEBUG_STR(m_msg), ERR_HANDLER_WARNING); \
- warning_shown = true; \
+ warning_shown.set(); \
} \
} else \
((void)0)
diff --git a/core/input/default_controller_mappings.h b/core/input/default_controller_mappings.h
index 9e2a69acec..ba5e650226 100644
--- a/core/input/default_controller_mappings.h
+++ b/core/input/default_controller_mappings.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 180708cea6..668a531b1f 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -1,4 +1,4 @@
-# Game Controller DB for SDL in 2.0.10 format
+# Game Controller DB for SDL in 2.0.9 format
# Source: https://github.com/gabomdq/SDL_GameControllerDB
# Windows
@@ -35,7 +35,7 @@
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000031000000000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000a00500003232000000000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -80,14 +80,15 @@
030000007d0400000840000000000000,Destroyer Tiltpad,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows,
03000000791d00000103000000000000,Dual Box WII,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
03000000bd12000002e0000000000000,Dual USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
+030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
030000006f0e00003001000000000000,EA SPORTS PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
03000000341a00000108000000000000,EXEQ RF USB Gamepad 8206,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
-030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,
-030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,
+030000006f0e00008401000000000000,Faceoff Deluxe+ Audio Wired Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000006f0e00008001000000000000,Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000852100000201000000000000,FF-GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008500000000000000,Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00008400000000000000,Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -98,6 +99,7 @@
03000000790000002201000000000000,Game Controller for PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
03000000260900002625000000000000,Gamecube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,
+03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
030000008f0e00000d31000000000000,GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000280400000140000000000000,GamePad Pro USB,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000ac0500003d03000000000000,GameSir,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
@@ -119,6 +121,7 @@
030000007d0400000540000000000000,Gravis Eliminator GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00004900000000000000,Hatsune Miku Sho Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+030000001008000001e1000000000000,Havit HV-G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
03000000d81400000862000000000000,HitBox Edition Cthulhu+,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
03000000632500002605000000000000,HJD-X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -164,7 +167,8 @@
030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000018c2000000000000,Logitech F510 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000019c2000000000000,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b6,righttrigger:b7,platform:Windows,
+030000006d0400001ac2000000000000,Logitech Precision Gamepad,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
+030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows,
03000000380700006652000000000000,Mad Catz C.T.R.L.R,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000380700005032000000000000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000380700005082000000000000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -193,6 +197,8 @@
03000000380700006382000000000000,MLG GamePad PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000c62400002a89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c62400002b89000000000000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400001a89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000c62400001b89000000000000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
030000006b140000010c000000000000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -234,6 +240,7 @@
030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
+030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00000011000000000000,QanBa Arcade JoyStick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows,
03000000300f00001611000000000000,QanBa Arcade JoyStick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
03000000222c00000020000000000000,QANBA DRONE ARCADE JOYSTICK,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows,
@@ -244,7 +251,6 @@
03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000321500000204000000000000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000104000000000000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b13,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:a3,righttrigger:a4,
03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000321500000011000000000000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -259,6 +265,7 @@
030000000d0f00005b00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00005c00000000000000,Real Arcade Pro.V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000790000001100000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
+03000000bd12000013d0000000000000,Retrolink USB SEGA Saturn Classic,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
0300000000f000000300000000000000,RetroUSB.com RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
0300000000f00000f100000000000000,RetroUSB.com Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -271,8 +278,8 @@
03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000a306000023f6000000000000,Saitek Cyborg V.1 Game pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00001201000000000000,Saitek Dual Analog Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
-03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b0,y:b1,platform:Windows,
-03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,x:b0,y:b1,platform:Windows,
+03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows,
+03000000a30600000cff000000000000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows,
03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
03000000300f00001001000000000000,Saitek P480 Rumble Pad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
@@ -283,6 +290,8 @@
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
0300000000050000289b000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
030000009b2800000500000000000000,Saturn_Adapter_2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
+03000000a30c00002500000000000000,Sega Genesis Mini 3B controller,a:b2,b:b1,start:b9,dpup:-a4,dpdown:+a4,dpleft:-a3,dpright:+a3,righttrigger:b5,platform:Windows,
+03000000a30c00002400000000000000,Sega Mega Drive Mini 6B controller,a:b2,b:b1,start:b9,dpup:-a4,dpdown:+a4,dpleft:-a3,dpright:+a3,rightshoulder:b4,righttrigger:b5,x:b3,y:b0,platform:Windows,
030000005e0400008e02000000007801,ShanWan PS3/PC Wired GamePad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000208000000000000,SL-6555-SBK,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000908000000000000,SL-6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
@@ -328,6 +337,8 @@
030000006f0e00000702000000000000,Victrix Pro Fight Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:+a3,righty:+a4,start:b4,x:b2,y:b3,platform:Windows,
030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000ff02000000007801,Xbox One Elite Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000450c00002043000000000000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000ac0500005b05000000000000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
@@ -338,7 +349,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000120c0000101e000000000000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
# Mac OS X
-030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Mac OS X,
+030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
@@ -355,12 +366,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000260000001000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
-03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000031000001000000,8BitDo Wireless Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000a00500003232000009010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
+03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
+03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -427,6 +440,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
+050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
03000000321500000204000000010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000321500000104000000010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -446,6 +460,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000b40400000a01000000000000,Sega Saturn USB Gamepad,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
+030000004c050000e60c000000010000,Sony DualSense,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000004c050000a00b000000000000,Sony DualShock 4 Wireless Adaptor,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
@@ -474,6 +489,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000d102000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000dd02000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
030000005e040000e302000000000000,Xbox One Wired Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
+030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
030000005e040000e002000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
030000005e040000e002000003090000,Xbox Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X,
030000005e040000ea02000000000000,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
@@ -506,12 +523,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
-03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
-05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000202800000900000000010000,8BitDo SNES30 Gamepad,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
-030000005e0400008e02000020010000,8BitDo Wireless Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-03000000c82d00000031000011010000,8BitDo Wireless Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+030000005e0400008e02000020010000,8BitDo Wireless Adapter (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+03000000c82d00000031000011010000,8BitDo Wireless Adapter (DInput),a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+050000005e040000e002000030110000,8BitDo Zero 2 (XInput),a:b0,b:b1,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,start:b7,x:b2,y:b3,platform:Linux,
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000a00500003232000001000000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
05000000a00500003232000008010000,8Bitdo Zero GamePad,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
@@ -521,11 +539,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00003901000013020000,Afterglow Prismatic Wired Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000100000008200000011010000,Akishop Customs PS360+ v1.66,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000007c1800000006000010010000,Alienware Dual Compatible Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
-05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000491900000204000021000000,Amazon Fire Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
03000000120c00000500000010010000,AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
+03000000c62400001b89000011010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000c21100000791000011010000,Be1 GC101 Controller 1.03 mode,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+03000000c31100000791000011010000,Be1 GC101 GAMEPAD 1.03 mode,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005e0400008e02000003030000,Be1 GC101 Xbox 360 Controller mode,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000666600006706000000010000,boom PSX to PC Converter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux,
03000000ffff0000ffff000000010000,Chinese-made Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -567,6 +590,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f0000aa00000011010000,HORI Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+030000000d0f0000d800000072056800,HORI Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
030000000d0f00001600000000010000,Hori Real Arcade Pro.EX-SE (Xbox 360),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00006e00000011010000,HORIPAD 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00006600000011010000,HORIPAD 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -592,6 +616,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000242f00002d00000011010000,JYS Wireless Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000242f00008a00000011010000,JYS Wireless Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux,
030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -600,10 +625,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
-030000006d04000015c2000010010000,Logitech Logitech Extreme 3D,a:b0,b:b4,back:b6,guide:b8,leftshoulder:b9,leftstick:h0.8,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:h0.2,start:b7,x:b2,y:b5,platform:Linux,
+030000006d0400000ac2000010010000,Logitech Inc. WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux,
030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux,
+050000004d4f435554452d3035305800,M54-PC,a:b0,b:b1,x:b3,y:b4,back:b10,start:b11,leftshoulder:b6,rightshoulder:b7,leftstick:b13,rightstick:b14,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,platform:Linux,
05000000380700006652000025010000,Mad Catz C.T.R.L.R ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005032000011010000,Mad Catz FightPad PRO (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000380700005082000011010000,Mad Catz FightPad PRO (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -635,6 +660,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e040000d102000003020000,Microsoft X-Box One pad v2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008502000000010000,Microsoft X-Box pad (Japan),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
+030000005e040000000b000008040000,Microsoft Xbox One Elite 2 pad - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000ea02000008040000,Microsoft Xbox One S pad - Wired,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400001a53000000010000,Mini PE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
05000000d6200000e589000001000000,Moga 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
@@ -642,12 +669,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000d62000007162000001000000,Moga Pro 2 HID,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
03000000c62400002b89000011010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000c62400002a89000000010000,MOGA XP5-A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c62400001a89000000010000,MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000250900006688000000010000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
030000006b140000010c000010010000,NACON GC-400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b6,start:b9,x:b3,y:b0,platform:Linux,
-060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
+060000007e0500000820000000000000,Nintendo Combined Joy-Cons (joycond),a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
+03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b0,y:b3,platform:Linux,
050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000920000001800000,Nintendo Switch Pro Controller (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
030000007e0500000920000011810000,Nintendo Switch Pro Controller Wired (joycond),a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux,
@@ -666,21 +695,23 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000830500005020000010010000,Padix Co. Ltd. Rockfire PSX/USB Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux,
03000000790000001c18000011010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
-030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,x:b2,y:b3,back:b6,guide:b8,start:b7,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
+030000006f0e0000b802000001010000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000006f0e0000b802000013020000,PDP AFTERGLOW Wired Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
+030000006f0e00008001000011010000,PDP CO. LTD. Faceoff Wired Pro Controller for Nintendo Switch,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006f0e00008701000011010000,PDP Rock Candy Wired Controller for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000006f0e00000901000011010000,PDP Versus Fighting Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e0000a802000023020000,PDP Wired Controller for Xbox One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
030000006f0e00008501000011010000,PDP Wired Fight Pad Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
+05000000491900000204000000000000,PG-9118,x:b76,a:b73,b:b74,y:b77,back:b83,start:b84,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b79,lefttrigger:b81,rightshoulder:b80,righttrigger:b82,leftstick:b86,rightstick:b87,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Linux,
0500000049190000030400001b010000,PG-9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
+03000000c62400001a58000001010000,PowerA Xbox One Cabled,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
@@ -709,6 +740,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
+030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
030000009b2800003200000001010000,Raphnet Technologies GC/N64 to USB v3.4,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
030000009b2800006000000001010000,Raphnet Technologies GC/N64 to USB v3.6,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
@@ -717,6 +750,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008916000000fd000024010000,Razer Onza Tournament Edition,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000321500000204000011010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000104000011010000,Razer Panthera (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000321500000810000011010000,Razer Panthera Evo Arcade Stick for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000010000011010000,Razer RAIJU,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000321500000011000011010000,Razer Raion Fightpad for PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
@@ -735,14 +769,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
-03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
+03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
+03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux,
+03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux,
03000000a30600000c04000011010000,Saitek P2900 Wireless Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux,
03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux,
03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux,
03000000a306000018f5000010010000,Saitek PLC Saitek P3200 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000a306000020f6000011010000,Saitek PS2700 Rumble Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
-03000000a30600001005000000010000,Saitek Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux,
03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux,
03000000c01600008704000011010000,Serial/Keyboard/Mouse/Joystick,a:b12,b:b10,back:b4,dpdown:b2,dpleft:b3,dpright:b1,dpup:b0,leftshoulder:b9,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b8,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b5,x:b13,y:b11,platform:Linux,
03000000f025000021c1000010010000,ShanWan Gioteck PS3 Wired Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -754,15 +789,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000005e0400008e02000073050000,Speedlink TORID Wireless Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000005e0400008e02000020200000,SpeedLink XEOX Pro Analog Gamepad pad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
+03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
-05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
+05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -774,11 +809,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
03000000457500002211000010010000,SZMY-POWER CO. LTD. GAMEPAD,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
030000008f0e00000d31000010010000,SZMY-POWER CO. LTD. GAMEPAD 3 TURBO,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000008f0e00001431000010010000,SZMY-POWER CO. LTD. PS3 gamepad,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux,
030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
030000004f0400000ed0000011010000,ThrustMaster eSwap PRO Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux,
+030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux,
030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux,
030000004f04000026b3000002040000,Thrustmaster Gamepad GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c6240000025b000002020000,Thrustmaster GPX Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
@@ -815,6 +852,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000e002000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000fd02000003090000,Xbox One Wireless Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e040000ea02000001030000,Xbox One Wireless Controller (Model 1708),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
+030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
030000005e0400008e02000000010000,xbox360 Wireless EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000450c00002043000010010000,XEOX Gamepad SL-6556-BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000ac0500005b05000010010000,Xiaoji Gamesir-G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
@@ -823,6 +864,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
+03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,
# Android
05000000c82d000006500000ffff3f00,8BitDo M30 Gamepad,a:b1,b:b0,back:b4,guide:b17,leftshoulder:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
@@ -857,20 +899,27 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
030000004c050000cc09000000006800,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android,
+32633532643734376632656664383733,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
+61303162353165316365336436343139,Sony DualSense,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android,
050000004f0400000ed00000fffe3f00,ThrustMaster eSwap PRO Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
5477696e20555342204a6f7973746963,Twin USB Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android,
30306539356238653637313730656134,Wireless HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
+050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e040000e00200000ffe3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android,
050000005e040000fd020000ffff3f00,Xbox One Wireless Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
050000005e04000091020000ff073f00,Xbox Wireless Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android,
34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android,
050000001727000044310000ffff3f00,XiaoMi Game Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android,
@@ -879,13 +928,20 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS,
+05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
-050000004c050000cc090000df070000,DUALSHOCK 4 Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,
4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
+050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,,platform:iOS,
+050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS,
05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS,
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS,
+050000005e040000050b0000ff070001,Xbox Elite Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
050000005e040000e0020000df070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
+050000005e040000e0020000ff070000,Xbox Wireless Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index 51ddda1e4e..c43cd6c8ac 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -8,13 +8,26 @@ __XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftst
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
# Javascript
-Default HTML5 Gamepad, Default Mapping,leftx:a0,lefty:a1,dpdown:b13,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a3,dpleft:b14,lefttrigger:a6,x:b2,dpup:b12,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b0,dpright:b15,righttrigger:a7,b:b1,platform:Javascript,
-c2a94d6963726f736f66742058626f78,Wireless X360 Controller,leftx:a0,lefty:a1,dpdown:b14,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:b11,lefttrigger:a2,x:b2,dpup:b13,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:b12,righttrigger:a5,b:b1,platform:Javascript,
-303534632d303563342d576972656c65,PS4 Controller USB/Win,leftx:a0,lefty:a1,dpdown:b15,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a5,lefttrigger:a3,x:b0,dpup:b14,dpleft:b16,dpright:b17,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b1,righttrigger:b7,b:b2,platform:Javascript,
-303534632d303563342d536f6e792043,PS4 Controller USB/Linux,leftx:a0,lefty:a1,dpdown:a7,rightstick:b11,rightshoulder:b5,rightx:a2,start:b9,righty:a5,dpleft:a6,lefttrigger:a3,x:b0,dpup:a7,back:b8,leftstick:b10,leftshoulder:b4,y:b3,a:b1,dpright:a6,righttrigger:a4,b:b2,platform:Javascript,
-303534632d303236382d536f6e792050,PS3 Controller USB/Linux,leftx:a0,lefty:a1,dpdown:b6,rightstick:b2,rightshoulder:b11,rightx:a2,start:b3,righty:a3,dpleft:b7,lefttrigger:b8,x:b15,dpup:b4,back:b0,leftstick:b1,leftshoulder:b10,y:b12,a:b14,dpright:b5,righttrigger:b9,b:b13,platform:Javascript,
-303435652d303731392d58626f782033,Wireless X360 Controller,leftx:a0,lefty:a1,dpdown:b14,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:b11,lefttrigger:a2,x:b2,dpup:b13,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:b12,righttrigger:a5,b:b1,platform:Javascript,
-303435652d303238652d4d6963726f73,Wired X360 Controller,leftx:a0,lefty:a1,dpdown:a7,rightstick:b10,rightshoulder:b5,rightx:a3,start:b7,righty:a4,dpleft:a6,lefttrigger:a2,x:b2,dpup:a7,back:b6,leftstick:b9,leftshoulder:b4,y:b3,a:b0,dpright:a6,righttrigger:a5,b:b1,platform:Javascript,
+standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Javascript,
+Linux24c6581a,PowerA Xbox One Cabled,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
+Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
+Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
+Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
+Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
+Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
+Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Javascript,
+Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Javascript,
+MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
+MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
+MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
+MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
+MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
+Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript
+Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
+MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
+Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
+Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
+MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Javascript
# UWP
__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 153656e44a..f928ae7654 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -55,6 +55,12 @@ static const char *_joy_buttons[JOY_BUTTON_SDL_MAX] = {
"dpdown",
"dpleft",
"dpright",
+ "misc1",
+ "paddle1",
+ "paddle2",
+ "paddle3",
+ "paddle4",
+ "touchpad",
};
static const char *_joy_axes[JOY_AXIS_SDL_MAX] = {
@@ -91,11 +97,11 @@ void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
- ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed);
- ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed);
- ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released);
- ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength);
- ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_strength);
+ ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact_match"), &Input::is_action_just_pressed, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact_match"), &Input::is_action_just_released, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact_match"), &Input::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis);
ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f));
ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false));
@@ -234,51 +240,83 @@ bool Input::is_joy_button_pressed(int p_device, int p_button) const {
return joy_buttons_pressed.has(_combine_device(p_button, p_device));
}
-bool Input::is_action_pressed(const StringName &p_action) const {
- return action_state.has(p_action) && action_state[p_action].pressed;
+bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
+ return action_state.has(p_action) && action_state[p_action].pressed && (p_exact ? action_state[p_action].exact : true);
}
-bool Input::is_action_just_pressed(const StringName &p_action) const {
+bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return false;
}
+ if (p_exact && E->get().exact == false) {
+ return false;
+ }
+
if (Engine::get_singleton()->is_in_physics_frame()) {
return E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
- return E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames();
+ return E->get().pressed && E->get().process_frame == Engine::get_singleton()->get_process_frames();
}
}
-bool Input::is_action_just_released(const StringName &p_action) const {
+bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return false;
}
+ if (p_exact && E->get().exact == false) {
+ return false;
+ }
+
if (Engine::get_singleton()->is_in_physics_frame()) {
return !E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames();
} else {
- return !E->get().pressed && E->get().idle_frame == Engine::get_singleton()->get_idle_frames();
+ return !E->get().pressed && E->get().process_frame == Engine::get_singleton()->get_process_frames();
}
}
-float Input::get_action_strength(const StringName &p_action) const {
+float Input::get_action_strength(const StringName &p_action, bool p_exact) const {
+#ifdef DEBUG_ENABLED
+ bool has_action = InputMap::get_singleton()->has_action(p_action);
+ ERR_FAIL_COND_V_MSG(!has_action, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
+#endif
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return 0.0f;
}
+ if (p_exact && E->get().exact == false) {
+ return 0.0f;
+ }
+
return E->get().strength;
}
-float Input::get_action_raw_strength(const StringName &p_action) const {
+float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const {
const Map<StringName, Action>::Element *E = action_state.find(p_action);
if (!E) {
return 0.0f;
}
+ if (p_exact && E->get().exact == false) {
+ return 0.0f;
+ }
+
return E->get().raw_strength;
}
@@ -582,20 +620,21 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
}
}
- for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) {
- if (InputMap::get_singleton()->event_is_action(p_event, E->key())) {
- // Save the action's state
- if (!p_event->is_echo() && is_action_pressed(E->key()) != p_event->is_action_pressed(E->key())) {
+ for (OrderedHashMap<StringName, InputMap::Action>::ConstElement E = InputMap::get_singleton()->get_action_map().front(); E; E = E.next()) {
+ if (InputMap::get_singleton()->event_is_action(p_event, E.key())) {
+ // If not echo and action pressed state has changed
+ if (!p_event->is_echo() && is_action_pressed(E.key(), false) != p_event->is_action_pressed(E.key())) {
Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.idle_frame = Engine::get_singleton()->get_idle_frames();
- action.pressed = p_event->is_action_pressed(E->key());
+ action.process_frame = Engine::get_singleton()->get_process_frames();
+ action.pressed = p_event->is_action_pressed(E.key());
action.strength = 0.0f;
action.raw_strength = 0.0f;
- action_state[E->key()] = action;
+ action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key(), true);
+ action_state[E.key()] = action;
}
- action_state[E->key()].strength = p_event->get_action_strength(E->key());
- action_state[E->key()].raw_strength = p_event->get_action_raw_strength(E->key());
+ action_state[E.key()].strength = p_event->get_action_strength(E.key());
+ action_state[E.key()].raw_strength = p_event->get_action_raw_strength(E.key());
}
}
@@ -714,7 +753,7 @@ void Input::action_press(const StringName &p_action, float p_strength) {
Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.idle_frame = Engine::get_singleton()->get_idle_frames();
+ action.process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = true;
action.strength = p_strength;
@@ -725,7 +764,7 @@ void Input::action_release(const StringName &p_action) {
Action action;
action.physics_frame = Engine::get_singleton()->get_physics_frames();
- action.idle_frame = Engine::get_singleton()->get_idle_frames();
+ action.process_frame = Engine::get_singleton()->get_process_frames();
action.pressed = false;
action.strength = 0.f;
@@ -806,7 +845,7 @@ void Input::accumulate_input_event(const Ref<InputEvent> &p_event) {
parse_input_event(p_event);
return;
}
- if (!accumulated_events.empty() && accumulated_events.back()->get()->accumulate(p_event)) {
+ if (!accumulated_events.is_empty() && accumulated_events.back()->get()->accumulate(p_event)) {
return; //event was accumulated, exit
}
@@ -886,10 +925,10 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) {
jx.min = p_value.min;
jx.value = p_value.value < 0.5 ? 0.6 : 0.4;
joy_axis(p_device, p_axis, jx);
- } else if (ABS(last) > 0.5 && last * p_value.value < 0) {
+ } else if (ABS(last) > 0.5 && last * p_value.value <= 0) {
JoyAxis jx;
jx.min = p_value.min;
- jx.value = p_value.value < 0 ? 0.1 : -0.1;
+ jx.value = last > 0 ? 0.1 : -0.1;
joy_axis(p_device, p_axis, jx);
}
diff --git a/core/input/input.h b/core/input/input.h
index 1b2df49ac0..0e3af42381 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -114,8 +114,9 @@ private:
struct Action {
uint64_t physics_frame;
- uint64_t idle_frame;
+ uint64_t process_frame;
bool pressed;
+ bool exact;
float strength;
float raw_strength;
};
@@ -261,11 +262,11 @@ public:
bool is_key_pressed(int p_keycode) const;
bool is_mouse_button_pressed(int p_button) const;
bool is_joy_button_pressed(int p_device, int p_button) const;
- bool is_action_pressed(const StringName &p_action) const;
- bool is_action_just_pressed(const StringName &p_action) const;
- bool is_action_just_released(const StringName &p_action) const;
- float get_action_strength(const StringName &p_action) const;
- float get_action_raw_strength(const StringName &p_action) const;
+ bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
+ bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const;
+ bool is_action_just_released(const StringName &p_action, bool p_exact = false) const;
+ float get_action_strength(const StringName &p_action, bool p_exact = false) const;
+ float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const;
float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const;
Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const;
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index e04e642f6b..c6910d2b1f 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -44,31 +44,31 @@ int InputEvent::get_device() const {
return device;
}
-bool InputEvent::is_action(const StringName &p_action) const {
- return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action);
+bool InputEvent::is_action(const StringName &p_action, bool p_exact_match) const {
+ return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match);
}
-bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo) const {
+bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo, bool p_exact_match) const {
bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && pressed && (p_allow_echo || !is_echo());
}
-bool InputEvent::is_action_released(const StringName &p_action) const {
+bool InputEvent::is_action_released(const StringName &p_action, bool p_exact_match) const {
bool pressed;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr);
return valid && !pressed;
}
-float InputEvent::get_action_strength(const StringName &p_action) const {
+float InputEvent::get_action_strength(const StringName &p_action, bool p_exact_match) const {
float strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, &strength);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, &strength, nullptr);
return valid ? strength : 0.0f;
}
-float InputEvent::get_action_raw_strength(const StringName &p_action) const {
+float InputEvent::get_action_raw_strength(const StringName &p_action, bool p_exact_match) const {
float raw_strength;
- bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, nullptr, &raw_strength);
+ bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, nullptr, &raw_strength);
return valid ? raw_strength : 0.0f;
}
@@ -100,10 +100,10 @@ void InputEvent::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device);
ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device);
- ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action);
- ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo"), &InputEvent::is_action_pressed, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released);
- ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength);
+ ClassDB::bind_method(D_METHOD("is_action", "action", "exact_match"), &InputEvent::is_action, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo", "exact_match"), &InputEvent::is_action_pressed, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("is_action_released", "action", "exact_match"), &InputEvent::is_action_released, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &InputEvent::get_action_strength, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed);
ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo);
@@ -210,10 +210,10 @@ String InputEventWithModifiers::as_text() const {
mod_names.push_back(find_keycode_name(KEY_META));
}
- if (!mod_names.empty()) {
+ if (!mod_names.is_empty()) {
return String("+").join(mod_names);
} else {
- return "None";
+ return "";
}
}
@@ -369,11 +369,44 @@ String InputEventKey::to_string() {
String p = is_pressed() ? "true" : "false";
String e = is_echo() ? "true" : "false";
+ String kc = "";
+ String physical = "false";
if (keycode == 0) {
- return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", itos(physical_keycode) + " " + keycode_get_string(physical_keycode), InputEventWithModifiers::as_text(), "true", p, e);
+ kc = itos(physical_keycode) + " " + keycode_get_string(physical_keycode);
+ physical = "true";
} else {
- return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", itos(keycode) + " " + keycode_get_string(keycode), InputEventWithModifiers::as_text(), "false", p, e);
+ kc = itos(keycode) + " " + keycode_get_string(keycode);
}
+
+ String mods = InputEventWithModifiers::as_text();
+ mods = mods == "" ? TTR("None") : mods;
+
+ return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e);
+}
+
+Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) {
+ Ref<InputEventKey> ie;
+ ie.instance();
+ ie->set_keycode(p_keycode & KEY_CODE_MASK);
+ ie->set_unicode(p_keycode & KEY_CODE_MASK);
+
+ if (p_keycode & KEY_MASK_SHIFT) {
+ ie->set_shift(true);
+ }
+ if (p_keycode & KEY_MASK_ALT) {
+ ie->set_alt(true);
+ }
+ if (p_keycode & KEY_MASK_CTRL) {
+ ie->set_control(true);
+ }
+ if (p_keycode & KEY_MASK_CMD) {
+ ie->set_command(true);
+ }
+ if (p_keycode & KEY_MASK_META) {
+ ie->set_metakey(true);
+ }
+
+ return ie;
}
bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const {
@@ -633,7 +666,12 @@ String InputEventMouseButton::to_string() {
break;
}
- return vformat("InputEventMouseButton: button_index=%s pressed=%s position=(%s) button_mask=%s doubleclick=%s", button_index, p, String(get_position()), itos(get_button_mask()), d);
+ String mods = InputEventWithModifiers::as_text();
+ mods = mods == "" ? TTR("None") : mods;
+
+ // Work around the fact vformat can only take 5 substitutions but 6 need to be passed.
+ String index_and_mods = vformat("button_index=%s mods=%s", button_index, mods);
+ return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s doubleclick=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d);
}
void InputEventMouseButton::_bind_methods() {
@@ -972,6 +1010,12 @@ static const char *_joy_button_descriptions[JOY_BUTTON_SDL_MAX] = {
TTRC("D-pad Down"),
TTRC("D-pad Left"),
TTRC("D-pad Right"),
+ TTRC("Xbox Share, PS5 Microphone, Nintendo Capture"),
+ TTRC("Xbox Paddle 1"),
+ TTRC("Xbox Paddle 2"),
+ TTRC("Xbox Paddle 3"),
+ TTRC("Xbox Paddle 4"),
+ TTRC("PS4/5 Touchpad"),
};
String InputEventJoypadButton::as_text() const {
@@ -992,6 +1036,14 @@ String InputEventJoypadButton::to_string() {
return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure));
}
+Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(int p_btn_index) {
+ Ref<InputEventJoypadButton> ie;
+ ie.instance();
+ ie->set_button_index(p_btn_index);
+
+ return ie;
+}
+
void InputEventJoypadButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_index", "button_index"), &InputEventJoypadButton::set_button_index);
ClassDB::bind_method(D_METHOD("get_button_index"), &InputEventJoypadButton::get_button_index);
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 6a71a24c8b..df81b9fc75 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -76,7 +76,13 @@ enum JoyButtonList {
JOY_BUTTON_DPAD_DOWN = 12,
JOY_BUTTON_DPAD_LEFT = 13,
JOY_BUTTON_DPAD_RIGHT = 14,
- JOY_BUTTON_SDL_MAX = 15,
+ JOY_BUTTON_MISC1 = 15,
+ JOY_BUTTON_PADDLE1 = 16,
+ JOY_BUTTON_PADDLE2 = 17,
+ JOY_BUTTON_PADDLE3 = 18,
+ JOY_BUTTON_PADDLE4 = 19,
+ JOY_BUTTON_TOUCHPAD = 20,
+ JOY_BUTTON_SDL_MAX = 21,
JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons.
};
@@ -122,11 +128,11 @@ public:
void set_device(int p_device);
int get_device() const;
- bool is_action(const StringName &p_action) const;
- bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const;
- bool is_action_released(const StringName &p_action) const;
- float get_action_strength(const StringName &p_action) const;
- float get_action_raw_strength(const StringName &p_action) const;
+ bool is_action(const StringName &p_action, bool p_exact_match = false) const;
+ bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const;
+ bool is_action_released(const StringName &p_action, bool p_exact_match = false) const;
+ float get_action_strength(const StringName &p_action, bool p_exact_match = false) const;
+ float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const;
// To be removed someday, since they do not make sense for all events
virtual bool is_pressed() const;
@@ -254,6 +260,8 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
+ static Ref<InputEventKey> create_reference(uint32_t p_keycode_with_modifier_masks);
+
InputEventKey() {}
};
@@ -400,6 +408,8 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
+ static Ref<InputEventJoypadButton> create_reference(int p_btn_index);
+
InputEventJoypadButton() {}
};
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 979809c7af..e0b25fa092 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -50,7 +50,7 @@ void InputMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event);
ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events);
ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events);
- ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action);
+ ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false));
ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings);
}
@@ -71,7 +71,7 @@ void InputMap::erase_action(const StringName &p_action) {
Array InputMap::_get_actions() {
Array ret;
List<StringName> actions = get_actions();
- if (actions.empty()) {
+ if (actions.is_empty()) {
return ret;
}
@@ -84,18 +84,18 @@ Array InputMap::_get_actions() {
List<StringName> InputMap::get_actions() const {
List<StringName> actions = List<StringName>();
- if (input_map.empty()) {
+ if (input_map.is_empty()) {
return actions;
}
- for (Map<StringName, Action>::Element *E = input_map.front(); E; E = E->next()) {
- actions.push_back(E->key());
+ for (OrderedHashMap<StringName, Action>::Element E = input_map.front(); E; E = E.next()) {
+ actions.push_back(E.key());
}
return actions;
}
-List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
+List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
ERR_FAIL_COND_V(!p_event.is_valid(), nullptr);
for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) {
@@ -106,7 +106,9 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re
int device = e->get_device();
if (device == ALL_DEVICES || device == p_event->get_device()) {
- if (e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) {
+ if (p_exact_match && e->shortcut_match(p_event)) {
+ return E;
+ } else if (!p_exact_match && e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) {
return E;
}
}
@@ -134,7 +136,7 @@ void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone)
void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object.");
ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
- if (_find_event(input_map[p_action], p_event)) {
+ if (_find_event(input_map[p_action], p_event, true)) {
return; // Already addded.
}
@@ -143,13 +145,13 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent
bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
- return (_find_event(input_map[p_action], p_event) != nullptr);
+ return (_find_event(input_map[p_action], p_event, true) != nullptr);
}
void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) {
ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'.");
- List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event);
+ List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true);
if (E) {
input_map[p_action].inputs.erase(E);
if (Input::get_singleton()->is_action_pressed(p_action)) {
@@ -177,20 +179,20 @@ Array InputMap::_action_get_events(const StringName &p_action) {
}
const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_action) {
- const Map<StringName, Action>::Element *E = input_map.find(p_action);
+ const OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
if (!E) {
return nullptr;
}
- return &E->get().inputs;
+ return &E.get().inputs;
}
-bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const {
- return event_get_action_status(p_event, p_action);
+bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const {
+ return event_get_action_status(p_event, p_action, p_exact_match);
}
-bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
- Map<StringName, Action>::Element *E = input_map.find(p_action);
+bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const {
+ OrderedHashMap<StringName, Action>::Element E = input_map.find(p_action);
ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'.");
Ref<InputEventAction> input_event_action = p_event;
@@ -207,7 +209,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
bool pressed;
float strength;
float raw_strength;
- List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength, &raw_strength);
+ List<Ref<InputEvent>>::Element *event = _find_event(E.get(), p_event, p_exact_match, &pressed, &strength, &raw_strength);
if (event != nullptr) {
if (p_pressed != nullptr) {
*p_pressed = pressed;
@@ -224,7 +226,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str
}
}
-const Map<StringName, InputMap::Action> &InputMap::get_action_map() const {
+const OrderedHashMap<StringName, InputMap::Action> &InputMap::get_action_map() const {
return input_map;
}
@@ -258,84 +260,444 @@ void InputMap::load_from_project_settings() {
}
}
+struct _BuiltinActionDisplayName {
+ const char *name;
+ const char *display_name;
+};
+
+static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
+ /* clang-format off */
+ { "ui_accept", TTRC("Accept") },
+ { "ui_select", TTRC("Select") },
+ { "ui_cancel", TTRC("Cancel") },
+ { "ui_focus_next", TTRC("Focus Next") },
+ { "ui_focus_prev", TTRC("Focus Prev") },
+ { "ui_left", TTRC("Left") },
+ { "ui_right", TTRC("Right") },
+ { "ui_up", TTRC("Up") },
+ { "ui_down", TTRC("Down") },
+ { "ui_page_up", TTRC("Page Up") },
+ { "ui_page_down", TTRC("Page Down") },
+ { "ui_home", TTRC("Home") },
+ { "ui_end", TTRC("End") },
+ { "ui_cut", TTRC("Cut") },
+ { "ui_copy", TTRC("Copy") },
+ { "ui_paste", TTRC("Paste") },
+ { "ui_undo", TTRC("Undo") },
+ { "ui_redo", TTRC("Redo") },
+ { "ui_text_completion_query", TTRC("Completion Query") },
+ { "ui_text_newline", TTRC("New Line") },
+ { "ui_text_newline_blank", TTRC("New Blank Line") },
+ { "ui_text_newline_above", TTRC("New Line Above") },
+ { "ui_text_indent", TTRC("Indent") },
+ { "ui_text_dedent", TTRC("Dedent") },
+ { "ui_text_backspace", TTRC("Backspace") },
+ { "ui_text_backspace_word", TTRC("Backspace Word") },
+ { "ui_text_backspace_word.OSX", TTRC("Backspace Word") },
+ { "ui_text_backspace_all_to_left", TTRC("Backspace all to Left") },
+ { "ui_text_backspace_all_to_left.OSX", TTRC("Backspace all to Left") },
+ { "ui_text_delete", TTRC("Delete") },
+ { "ui_text_delete_word", TTRC("Delete Word") },
+ { "ui_text_delete_word.OSX", TTRC("Delete Word") },
+ { "ui_text_delete_all_to_right", TTRC("Delete all to Right") },
+ { "ui_text_delete_all_to_right.OSX", TTRC("Delete all to Right") },
+ { "ui_text_caret_left", TTRC("Caret Left") },
+ { "ui_text_caret_word_left", TTRC("Caret Word Left") },
+ { "ui_text_caret_word_left.OSX", TTRC("Caret Word Left") },
+ { "ui_text_caret_right", TTRC("Caret Right") },
+ { "ui_text_caret_word_right", TTRC("Caret Word Right") },
+ { "ui_text_caret_word_right.OSX", TTRC("Caret Word Right") },
+ { "ui_text_caret_up", TTRC("Caret Up") },
+ { "ui_text_caret_down", TTRC("Caret Down") },
+ { "ui_text_caret_line_start", TTRC("Caret Line Start") },
+ { "ui_text_caret_line_start.OSX", TTRC("Caret Line Start") },
+ { "ui_text_caret_line_end", TTRC("Caret Line End") },
+ { "ui_text_caret_line_end.OSX", TTRC("Caret Line End") },
+ { "ui_text_caret_page_up", TTRC("Caret Page Up") },
+ { "ui_text_caret_page_down", TTRC("Caret Page Down") },
+ { "ui_text_caret_document_start", TTRC("Caret Document Start") },
+ { "ui_text_caret_document_start.OSX", TTRC("Caret Document Start") },
+ { "ui_text_caret_document_end", TTRC("Caret Document End") },
+ { "ui_text_caret_document_end.OSX", TTRC("Caret Document End") },
+ { "ui_text_scroll_up", TTRC("Scroll Up") },
+ { "ui_text_scroll_up.OSX", TTRC("Scroll Up") },
+ { "ui_text_scroll_down", TTRC("Scroll Down") },
+ { "ui_text_scroll_down.OSX", TTRC("Scroll Down") },
+ { "ui_text_select_all", TTRC("Select All") },
+ { "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
+ { "ui_graph_duplicate", TTRC("Duplicate Nodes") },
+ { "ui_graph_delete", TTRC("Delete Nodes") },
+ { "ui_filedialog_up_one_level", TTRC("Go Up One Level") },
+ { "ui_filedialog_refresh", TTRC("Refresh") },
+ { "ui_filedialog_show_hidden", TTRC("Show Hidden") },
+ { "ui_swap_input_direction ", TTRC("Swap Input Direction") },
+ { "", TTRC("")}
+ /* clang-format on */
+};
+
+String InputMap::get_builtin_display_name(const String &p_name) const {
+ int len = sizeof(_builtin_action_display_names) / sizeof(_BuiltinActionDisplayName);
+
+ for (int i = 0; i < len; i++) {
+ if (_builtin_action_display_names[i].name == p_name) {
+ return RTR(_builtin_action_display_names[i].display_name);
+ }
+ }
+
+ return p_name;
+}
+
+const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
+ // Return cache if it has already been built.
+ if (default_builtin_cache.size()) {
+ return default_builtin_cache;
+ }
+
+ List<Ref<InputEvent>> inputs;
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_SPACE));
+ default_builtin_cache.insert("ui_accept", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_Y));
+ inputs.push_back(InputEventKey::create_reference(KEY_SPACE));
+ default_builtin_cache.insert("ui_select", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ESCAPE));
+ default_builtin_cache.insert("ui_cancel", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_focus_next", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_focus_prev", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_LEFT));
+ default_builtin_cache.insert("ui_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_RIGHT));
+ default_builtin_cache.insert("ui_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_UP));
+ default_builtin_cache.insert("ui_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN));
+ inputs.push_back(InputEventJoypadButton::create_reference(JOY_BUTTON_DPAD_DOWN));
+ default_builtin_cache.insert("ui_down", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEUP));
+ default_builtin_cache.insert("ui_page_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEDOWN));
+ default_builtin_cache.insert("ui_page_down", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_HOME));
+ default_builtin_cache.insert("ui_home", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_END));
+ default_builtin_cache.insert("ui_end", inputs);
+
+ // ///// UI basic Shortcuts /////
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_X | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_cut", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_C | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_INSERT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_copy", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_V | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_INSERT | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_paste", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_Z | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_undo", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_Z | KEY_MASK_CMD | KEY_MASK_SHIFT));
+ inputs.push_back(InputEventKey::create_reference(KEY_Y | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_redo", inputs);
+
+ // ///// UI Text Input Shortcuts /////
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_SPACE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_completion_query", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_text_completion_accept", inputs);
+
+ // Newlines
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER));
+ default_builtin_cache.insert("ui_text_newline", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_newline_blank", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER | KEY_MASK_SHIFT | KEY_MASK_CMD));
+ inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER | KEY_MASK_SHIFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_newline_above", inputs);
+
+ // Indentation
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ default_builtin_cache.insert("ui_text_indent", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_TAB | KEY_MASK_SHIFT));
+ default_builtin_cache.insert("ui_text_dedent", inputs);
+
+ // Text Backspace and Delete
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE));
+ default_builtin_cache.insert("ui_text_backspace", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_backspace_word", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_backspace_word.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ default_builtin_cache.insert("ui_text_backspace_all_to_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_backspace_all_to_left.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE));
+ default_builtin_cache.insert("ui_text_delete", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_delete_word", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_delete_word.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ default_builtin_cache.insert("ui_text_delete_all_to_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_delete_all_to_right.OSX", inputs);
+
+ // Text Caret Movement Left/Right
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT));
+ default_builtin_cache.insert("ui_text_caret_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_word_left", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_caret_word_left.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT));
+ default_builtin_cache.insert("ui_text_caret_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_word_right", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_caret_word_right.OSX", inputs);
+
+ // Text Caret Movement Up/Down
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP));
+ default_builtin_cache.insert("ui_text_caret_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN));
+ default_builtin_cache.insert("ui_text_caret_down", inputs);
+
+ // Text Caret Movement Line Start/End
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_HOME));
+ default_builtin_cache.insert("ui_text_caret_line_start", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_A | KEY_MASK_CTRL));
+ inputs.push_back(InputEventKey::create_reference(KEY_LEFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_line_start.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_END));
+ default_builtin_cache.insert("ui_text_caret_line_end", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_E | KEY_MASK_CTRL));
+ inputs.push_back(InputEventKey::create_reference(KEY_RIGHT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_line_end.OSX", inputs);
+ // Text Caret Movement Page Up/Down
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEUP));
+ default_builtin_cache.insert("ui_text_caret_page_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_PAGEDOWN));
+ default_builtin_cache.insert("ui_text_caret_page_down", inputs);
+
+ // Text Caret Movement Document Start/End
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_HOME | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_start", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_start.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_END | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_end", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_caret_document_end.OSX", inputs);
+
+ // Text Scrolling
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_scroll_up", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_UP | KEY_MASK_CMD | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_scroll_up.OSX", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_scroll_down", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DOWN | KEY_MASK_CMD | KEY_MASK_ALT));
+ default_builtin_cache.insert("ui_text_scroll_down.OSX", inputs);
+
+ // Text Misc
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_A | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_text_select_all", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_INSERT));
+ default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_MENU));
+ default_builtin_cache.insert("ui_menu", inputs);
+
+ // ///// UI Graph Shortcuts /////
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_D | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_graph_duplicate", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_DELETE));
+ default_builtin_cache.insert("ui_graph_delete", inputs);
+
+ // ///// UI File Dialog Shortcuts /////
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE));
+ default_builtin_cache.insert("ui_filedialog_up_one_level", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_F5));
+ default_builtin_cache.insert("ui_filedialog_refresh", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_H));
+ default_builtin_cache.insert("ui_filedialog_show_hidden", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(KEY_QUOTELEFT | KEY_MASK_CMD));
+ default_builtin_cache.insert("ui_swap_input_direction", inputs);
+
+ return default_builtin_cache;
+}
+
void InputMap::load_default() {
- Ref<InputEventKey> key;
-
- add_action("ui_accept");
- key.instance();
- key->set_keycode(KEY_ENTER);
- action_add_event("ui_accept", key);
-
- key.instance();
- key->set_keycode(KEY_KP_ENTER);
- action_add_event("ui_accept", key);
-
- key.instance();
- key->set_keycode(KEY_SPACE);
- action_add_event("ui_accept", key);
-
- add_action("ui_select");
- key.instance();
- key->set_keycode(KEY_SPACE);
- action_add_event("ui_select", key);
-
- add_action("ui_cancel");
- key.instance();
- key->set_keycode(KEY_ESCAPE);
- action_add_event("ui_cancel", key);
-
- add_action("ui_focus_next");
- key.instance();
- key->set_keycode(KEY_TAB);
- action_add_event("ui_focus_next", key);
-
- add_action("ui_focus_prev");
- key.instance();
- key->set_keycode(KEY_TAB);
- key->set_shift(true);
- action_add_event("ui_focus_prev", key);
-
- add_action("ui_left");
- key.instance();
- key->set_keycode(KEY_LEFT);
- action_add_event("ui_left", key);
-
- add_action("ui_right");
- key.instance();
- key->set_keycode(KEY_RIGHT);
- action_add_event("ui_right", key);
-
- add_action("ui_up");
- key.instance();
- key->set_keycode(KEY_UP);
- action_add_event("ui_up", key);
-
- add_action("ui_down");
- key.instance();
- key->set_keycode(KEY_DOWN);
- action_add_event("ui_down", key);
-
- add_action("ui_page_up");
- key.instance();
- key->set_keycode(KEY_PAGEUP);
- action_add_event("ui_page_up", key);
-
- add_action("ui_page_down");
- key.instance();
- key->set_keycode(KEY_PAGEDOWN);
- action_add_event("ui_page_down", key);
-
- add_action("ui_home");
- key.instance();
- key->set_keycode(KEY_HOME);
- action_add_event("ui_home", key);
-
- add_action("ui_end");
- key.instance();
- key->set_keycode(KEY_END);
- action_add_event("ui_end", key);
-
- //set("display/window/handheld/orientation", "landscape");
+ OrderedHashMap<String, List<Ref<InputEvent>>> builtins = get_builtins();
+
+ // List of Builtins which have an override for OSX.
+ Vector<String> osx_builtins;
+ for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+ if (String(E.key()).ends_with(".OSX")) {
+ // Strip .OSX from name: some_input_name.OSX -> some_input_name
+ osx_builtins.push_back(String(E.key()).split(".")[0]);
+ }
+ }
+
+ for (OrderedHashMap<String, List<Ref<InputEvent>>>::Element E = builtins.front(); E; E = E.next()) {
+ String fullname = E.key();
+ String name = fullname.split(".")[0];
+ String override_for = fullname.split(".").size() > 1 ? fullname.split(".")[1] : "";
+
+#ifdef APPLE_STYLE_KEYS
+ if (osx_builtins.has(name) && override_for != "OSX") {
+ // Name has osx builtin but this particular one is for non-osx systems - so skip.
+ continue;
+ }
+#else
+ if (override_for == "OSX") {
+ // Override for OSX - not needed on non-osx platforms.
+ continue;
+ }
+#endif
+
+ add_action(name);
+
+ List<Ref<InputEvent>> inputs = E.get();
+ for (List<Ref<InputEvent>>::Element *I = inputs.front(); I; I = I->next()) {
+ Ref<InputEventKey> iek = I->get();
+
+ // For the editor, only add keyboard actions.
+ if (iek.is_valid()) {
+ action_add_event(name, I->get());
+ }
+ }
+ }
}
InputMap::InputMap() {
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 948d78ebdd..99c71e1e53 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -33,6 +33,8 @@
#include "core/input/input_event.h"
#include "core/object/class_db.h"
+#include "core/object/object.h"
+#include "core/templates/ordered_hash_map.h"
class InputMap : public Object {
GDCLASS(InputMap, Object);
@@ -52,9 +54,10 @@ public:
private:
static InputMap *singleton;
- mutable Map<StringName, Action> input_map;
+ mutable OrderedHashMap<StringName, Action> input_map;
+ OrderedHashMap<String, List<Ref<InputEvent>>> default_builtin_cache;
- List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
+ List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
Array _action_get_events(const StringName &p_action);
Array _get_actions();
@@ -78,13 +81,17 @@ public:
void action_erase_events(const StringName &p_action);
const List<Ref<InputEvent>> *action_get_events(const StringName &p_action);
- bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const;
- bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
+ bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const;
+ bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const;
- const Map<StringName, Action> &get_action_map() const;
+ const OrderedHashMap<StringName, Action> &get_action_map() const;
void load_from_project_settings();
void load_default();
+ String get_builtin_display_name(const String &p_name) const;
+ // Use an Ordered Map so insertion order is preserved. We want the elements to be 'grouped' somewhat.
+ const OrderedHashMap<String, List<Ref<InputEvent>>> &get_builtins();
+
InputMap();
};
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 8e613cb3ce..456023e2a6 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/compression.h b/core/io/compression.h
index 864869788a..cbfed74124 100644
--- a/core/io/compression.h
+++ b/core/io/compression.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 8be39178db..015c1f0d90 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -67,7 +67,7 @@ void ConfigFile::set_value(const String &p_section, const String &p_key, const V
return; // ?
}
values[p_section].erase(p_key);
- if (values[p_section].empty()) {
+ if (values[p_section].is_empty()) {
values.erase(p_section);
}
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 1dc4492ca8..386d304f07 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp
index 1930f40c47..288b2efe0e 100644
--- a/core/io/dtls_server.cpp
+++ b/core/io/dtls_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/dtls_server.h b/core/io/dtls_server.h
index ae1d3bcd98..92b6caf508 100644
--- a/core/io/dtls_server.h
+++ b/core/io/dtls_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 4424192af2..9ec2b27e88 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -327,14 +327,14 @@ Error FileAccessCompressed::get_error() const {
void FileAccessCompressed::flush() {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
// compressed files keep data in memory till close()
}
void FileAccessCompressed::store_8(uint8_t p_dest) {
ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
WRITE_FIT(1);
write_ptr[write_pos++] = p_dest;
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 52284b347e..118d05ea57 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 2ac24d5169..8b4c57ce64 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -256,7 +256,7 @@ Error FileAccessEncrypted::get_error() const {
}
void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) {
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
if (pos < data.size()) {
for (int i = 0; i < p_length; i++) {
@@ -272,13 +272,13 @@ void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) {
}
void FileAccessEncrypted::flush() {
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
// encrypted files keep data in memory till close()
}
void FileAccessEncrypted::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(!writing, "File has not been opened in read mode.");
+ ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode.");
if (pos < data.size()) {
data.write[pos] = p_dest;
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index c760933038..969052d04f 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 79cba63765..04270de77f 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 47012b4e83..0e3b0ad7b1 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 1e9266f118..97838fd14c 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -201,7 +201,7 @@ Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const S
return ERR_INVALID_PARAMETER;
}
- thread = Thread::create(_thread_func, this);
+ thread.start(_thread_func, this);
return OK;
}
@@ -214,12 +214,9 @@ FileAccessNetworkClient::FileAccessNetworkClient() {
}
FileAccessNetworkClient::~FileAccessNetworkClient() {
- if (thread) {
- quit = true;
- sem.post();
- Thread::wait_to_finish(thread);
- memdelete(thread);
- }
+ quit = true;
+ sem.post();
+ thread.wait_to_finish();
}
void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) {
@@ -350,7 +347,7 @@ void FileAccessNetwork::_queue_page(int p_page) const {
if (p_page >= pages.size()) {
return;
}
- if (pages[p_page].buffer.empty() && !pages[p_page].queued) {
+ if (pages[p_page].buffer.is_empty() && !pages[p_page].queued) {
FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton;
{
MutexLock lock(nc->blockrequest_mutex);
@@ -386,7 +383,7 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const {
if (page != last_page) {
buffer_mutex.lock();
- if (pages[page].buffer.empty()) {
+ if (pages[page].buffer.is_empty()) {
waiting_on_page = page;
for (int j = 0; j < read_ahead; j++) {
_queue_page(page + j);
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index dc5ce1e883..1f5de3e5dd 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -48,7 +48,7 @@ class FileAccessNetworkClient {
List<BlockRequest> block_requests;
Semaphore sem;
- Thread *thread = nullptr;
+ Thread thread;
bool quit = false;
Mutex mutex;
Mutex blockrequest_mutex;
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index a025ca5730..faf4fca14f 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -89,7 +89,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o
}
String filename = path.get_file();
// Don't add as a file if the path points to a directory
- if (!filename.empty()) {
+ if (!filename.is_empty()) {
cd->files.insert(filename);
}
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index c13626a5aa..343adbe592 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -92,7 +92,7 @@ private:
PathMD5() {}
- PathMD5(const Vector<uint8_t> p_buf) {
+ PathMD5(const Vector<uint8_t> &p_buf) {
a = *((uint64_t *)&p_buf[0]);
b = *((uint64_t *)&p_buf[8]);
}
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 1163c409bc..01f9337a80 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index f8e7c1e587..8559f871ce 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 768fcdbb14..3863dce0f6 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -96,6 +96,11 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) {
ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object.");
+ if (ssl) {
+ ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()),
+ "Connection is not a reference to a valid StreamPeerSSL object.");
+ }
+
if (connection == p_connection) {
return;
}
@@ -736,14 +741,14 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
String query = "";
Array keys = p_dict.keys();
for (int i = 0; i < keys.size(); ++i) {
- String encoded_key = String(keys[i]).http_escape();
+ String encoded_key = String(keys[i]).uri_encode();
Variant value = p_dict[keys[i]];
switch (value.get_type()) {
case Variant::ARRAY: {
// Repeat the key with every values
Array values = value;
for (int j = 0; j < values.size(); ++j) {
- query += "&" + encoded_key + "=" + String(values[j]).http_escape();
+ query += "&" + encoded_key + "=" + String(values[j]).uri_encode();
}
break;
}
@@ -754,7 +759,7 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
}
default: {
// Add the key-value pair
- query += "&" + encoded_key + "=" + String(value).http_escape();
+ query += "&" + encoded_key + "=" + String(value).uri_encode();
}
}
}
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 3d9fe321ba..ec4b86b26f 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 7c32c02701..5d46d75efe 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -375,7 +375,7 @@ Image::Image3DValidateError Image::validate_3d_image(Image::Format p_format, int
if (idx >= p_images.size()) {
return VALIDATE_3D_ERR_MISSING_IMAGES;
}
- if (p_images[idx].is_null() || p_images[idx]->empty()) {
+ if (p_images[idx].is_null() || p_images[idx]->is_empty()) {
return VALIDATE_3D_ERR_IMAGE_EMPTY;
}
if (p_images[idx]->get_format() != p_format) {
@@ -993,7 +993,7 @@ bool Image::is_size_po2() const {
return uint32_t(width) == next_power_of_2(width) && uint32_t(height) == next_power_of_2(height);
}
-void Image::resize_to_po2(bool p_square) {
+void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
int w = next_power_of_2(width);
@@ -1008,7 +1008,7 @@ void Image::resize_to_po2(bool p_square) {
}
}
- resize(w, h);
+ resize(w, h, p_interpolation);
}
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
@@ -1753,10 +1753,10 @@ Error Image::generate_mipmaps(bool p_renormalize) {
Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, const Ref<Image> &p_normal_map) {
Vector<double> normal_sat_vec; //summed area table
- double *normal_sat = nullptr; //summed area table for normalmap
+ double *normal_sat = nullptr; //summed area table for normal map
int normal_w = 0, normal_h = 0;
- ERR_FAIL_COND_V_MSG(p_normal_map.is_null() || p_normal_map->empty(), ERR_INVALID_PARAMETER, "Must provide a valid normalmap for roughness mipmaps");
+ ERR_FAIL_COND_V_MSG(p_normal_map.is_null() || p_normal_map->is_empty(), ERR_INVALID_PARAMETER, "Must provide a valid normal map for roughness mipmaps");
Ref<Image> nm = p_normal_map->duplicate();
if (nm->is_compressed()) {
@@ -1950,7 +1950,7 @@ void Image::clear_mipmaps() {
return;
}
- if (empty()) {
+ if (is_empty()) {
return;
}
@@ -1961,7 +1961,7 @@ void Image::clear_mipmaps() {
mipmaps = false;
}
-bool Image::empty() const {
+bool Image::is_empty() const {
return (data.size() == 0);
}
@@ -2480,7 +2480,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po
ERR_FAIL_COND(format != p_src->format);
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot blit_rect in compressed or custom image formats.");
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2494,7 +2494,7 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
uint8_t *wp = data.ptrw();
uint8_t *dst_data_ptr = wp;
@@ -2535,7 +2535,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2549,7 +2549,7 @@ void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, co
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
uint8_t *wp = data.ptrw();
uint8_t *dst_data_ptr = wp;
@@ -2589,7 +2589,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P
ERR_FAIL_COND(srcdsize == 0);
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2603,7 +2603,7 @@ void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const P
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
Ref<Image> img = p_src;
@@ -2638,7 +2638,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
ERR_FAIL_COND_MSG(p_src->height != p_mask->height, "Source image height is different from mask height.");
ERR_FAIL_COND(format != p_src->format);
- Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect);
+ Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).intersection(p_src_rect);
if (p_dest.x < 0) {
clipped_src_rect.position.x = ABS(p_dest.x);
@@ -2652,7 +2652,7 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
}
Point2 src_underscan = Point2(MIN(0, p_src_rect.position.x), MIN(0, p_src_rect.position.y));
- Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
+ Rect2i dest_rect = Rect2i(0, 0, width, height).intersection(Rect2i(p_dest - src_underscan, clipped_src_rect.size));
Ref<Image> img = p_src;
Ref<Image> msk = p_mask;
@@ -2985,6 +2985,26 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) {
_set_color_at_ofs(data.ptrw(), ofs, p_color);
}
+void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) {
+ uint8_t *w = data.ptrw();
+ uint32_t pixel_size = get_format_pixel_size(format);
+ uint32_t pixel_count = data.size() / pixel_size;
+
+ for (uint32_t i = 0; i < pixel_count; i++) {
+ Color c = _get_color_at_ofs(w, i);
+ Vector3 rgb(c.r, c.g, c.b);
+
+ rgb *= p_brightness;
+ rgb = Vector3(0.5, 0.5, 0.5).lerp(rgb, p_contrast);
+ float center = (rgb.x + rgb.y + rgb.z) / 3.0;
+ rgb = Vector3(center, center, center).lerp(rgb, p_saturation);
+ c.r = rgb.x;
+ c.g = rgb.y;
+ c.b = rgb.z;
+ _set_color_at_ofs(w, i, c);
+ }
+}
+
Image::UsedChannels Image::detect_used_channels(CompressSource p_source) {
ERR_FAIL_COND_V(data.size() == 0, USED_CHANNELS_RGBA);
ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA);
@@ -3077,7 +3097,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mipmap_offset", "mipmap"), &Image::get_mipmap_offset);
- ClassDB::bind_method(D_METHOD("resize_to_po2", "square"), &Image::resize_to_po2, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("resize_to_po2", "square", "interpolation"), &Image::resize_to_po2, DEFVAL(false), DEFVAL(INTERPOLATE_BILINEAR));
ClassDB::bind_method(D_METHOD("resize", "width", "height", "interpolation"), &Image::resize, DEFVAL(INTERPOLATE_BILINEAR));
ClassDB::bind_method(D_METHOD("shrink_x2"), &Image::shrink_x2);
@@ -3090,7 +3110,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty);
ClassDB::bind_method(D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::_create_from_data);
- ClassDB::bind_method(D_METHOD("is_empty"), &Image::empty);
+ ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
ClassDB::bind_method(D_METHOD("load", "path"), &Image::load);
ClassDB::bind_method(D_METHOD("save_png", "path"), &Image::save_png);
@@ -3109,9 +3129,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("fix_alpha_edges"), &Image::fix_alpha_edges);
ClassDB::bind_method(D_METHOD("premultiply_alpha"), &Image::premultiply_alpha);
ClassDB::bind_method(D_METHOD("srgb_to_linear"), &Image::srgb_to_linear);
- ClassDB::bind_method(D_METHOD("normalmap_to_xy"), &Image::normalmap_to_xy);
+ ClassDB::bind_method(D_METHOD("normal_map_to_xy"), &Image::normal_map_to_xy);
ClassDB::bind_method(D_METHOD("rgbe_to_srgb"), &Image::rgbe_to_srgb);
- ClassDB::bind_method(D_METHOD("bumpmap_to_normalmap", "bump_scale"), &Image::bumpmap_to_normalmap, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("bump_map_to_normal_map", "bump_scale"), &Image::bump_map_to_normal_map, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("blit_rect", "src", "src_rect", "dst"), &Image::blit_rect);
ClassDB::bind_method(D_METHOD("blit_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blit_rect_mask);
@@ -3132,6 +3152,8 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pixelv", "point", "color"), &Image::set_pixelv);
ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel);
+ ClassDB::bind_method(D_METHOD("adjust_bcs", "brightness", "contrast", "saturation"), &Image::adjust_bcs);
+
ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer);
ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer);
ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer);
@@ -3220,7 +3242,7 @@ void Image::set_compress_bptc_func(void (*p_compress_func)(Image *, float, UsedC
_image_compress_bptc_func = p_compress_func;
}
-void Image::normalmap_to_xy() {
+void Image::normal_map_to_xy() {
convert(Image::FORMAT_RGBA8);
{
@@ -3285,7 +3307,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
return image;
}
-void Image::bumpmap_to_normalmap(float bump_scale) {
+void Image::bump_map_to_normal_map(float bump_scale) {
ERR_FAIL_COND(!_can_modify(format));
convert(Image::FORMAT_RF);
@@ -3585,7 +3607,7 @@ Image::Image(const uint8_t *p_mem_png_jpg, int p_len) {
copy_internals_from(_png_mem_loader_func(p_mem_png_jpg, p_len));
}
- if (empty() && _jpg_mem_loader_func) {
+ if (is_empty() && _jpg_mem_loader_func) {
copy_internals_from(_jpg_mem_loader_func(p_mem_png_jpg, p_len));
}
}
diff --git a/core/io/image.h b/core/io/image.h
index 0151df0cf9..df8f9b35a1 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -244,7 +244,7 @@ public:
/**
* Resize the image, using the preferred interpolation method.
*/
- void resize_to_po2(bool p_square = false);
+ void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void shrink_x2();
bool is_size_po2() const;
@@ -285,7 +285,7 @@ public:
/**
* returns true when the image is empty (0,0) in size
*/
- bool empty() const;
+ bool is_empty() const;
Vector<uint8_t> get_data() const;
@@ -350,10 +350,10 @@ public:
void fix_alpha_edges();
void premultiply_alpha();
void srgb_to_linear();
- void normalmap_to_xy();
+ void normal_map_to_xy();
Ref<Image> rgbe_to_srgb();
Ref<Image> get_image_from_mipmap(int p_mipamp) const;
- void bumpmap_to_normalmap(float bump_scale = 1.0);
+ void bump_map_to_normal_map(float bump_scale = 1.0);
void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest);
void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest);
@@ -390,6 +390,8 @@ public:
void set_pixelv(const Point2i &p_point, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);
+ void adjust_bcs(float p_brightness, float p_contrast, float p_saturation);
+
void set_as_black();
void copy_internals_from(const Ref<Image> &p_image) {
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index f6d8668349..7de038e6fe 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -122,7 +122,7 @@ void ImageLoader::cleanup() {
/////////////////
-RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
if (!f) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index d5fb4678eb..a5d588e0b5 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -72,7 +72,7 @@ public:
class ResourceFormatLoaderImage : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 9f3540efad..e1d9c19f10 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,13 +40,13 @@ VARIANT_ENUM_CAST(IP::ResolverStatus);
struct _IP_ResolverPrivate {
struct QueueItem {
- volatile IP::ResolverStatus status;
+ SafeNumeric<IP::ResolverStatus> status;
IP_Address response;
String hostname;
IP::Type type;
void clear() {
- status = IP::RESOLVER_STATUS_NONE;
+ status.set(IP::RESOLVER_STATUS_NONE);
response = IP_Address();
type = IP::TYPE_NONE;
hostname = "";
@@ -61,7 +61,7 @@ struct _IP_ResolverPrivate {
IP::ResolverID find_empty_id() const {
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
- if (queue[i].status == IP::RESOLVER_STATUS_NONE) {
+ if (queue[i].status.get() == IP::RESOLVER_STATUS_NONE) {
return i;
}
}
@@ -71,21 +71,21 @@ struct _IP_ResolverPrivate {
Mutex mutex;
Semaphore sem;
- Thread *thread;
+ Thread thread;
//Semaphore* semaphore;
bool thread_abort;
void resolve_queues() {
for (int i = 0; i < IP::RESOLVER_MAX_QUERIES; i++) {
- if (queue[i].status != IP::RESOLVER_STATUS_WAITING) {
+ if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) {
continue;
}
queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type);
if (!queue[i].response.is_valid()) {
- queue[i].status = IP::RESOLVER_STATUS_ERROR;
+ queue[i].status.set(IP::RESOLVER_STATUS_ERROR);
} else {
- queue[i].status = IP::RESOLVER_STATUS_DONE;
+ queue[i].status.set(IP::RESOLVER_STATUS_DONE);
}
}
}
@@ -137,11 +137,11 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
resolver->queue[id].type = p_type;
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
resolver->queue[id].response = resolver->cache[key];
- resolver->queue[id].status = IP::RESOLVER_STATUS_DONE;
+ resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
} else {
resolver->queue[id].response = IP_Address();
- resolver->queue[id].status = IP::RESOLVER_STATUS_WAITING;
- if (resolver->thread) {
+ resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
+ if (resolver->thread.is_started()) {
resolver->sem.post();
} else {
resolver->resolve_queues();
@@ -156,12 +156,12 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
MutexLock lock(resolver->mutex);
- if (resolver->queue[p_id].status == IP::RESOLVER_STATUS_NONE) {
+ if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) {
ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE");
resolver->mutex.unlock();
return IP::RESOLVER_STATUS_NONE;
}
- return resolver->queue[p_id].status;
+ return resolver->queue[p_id].status.get();
}
IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
@@ -169,7 +169,7 @@ IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
MutexLock lock(resolver->mutex);
- if (resolver->queue[p_id].status != IP::RESOLVER_STATUS_DONE) {
+ if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
resolver->mutex.unlock();
return IP_Address();
@@ -183,13 +183,13 @@ void IP::erase_resolve_item(ResolverID p_id) {
MutexLock lock(resolver->mutex);
- resolver->queue[p_id].status = IP::RESOLVER_STATUS_NONE;
+ resolver->queue[p_id].status.set(IP::RESOLVER_STATUS_NONE);
}
void IP::clear_cache(const String &p_hostname) {
MutexLock lock(resolver->mutex);
- if (p_hostname.empty()) {
+ if (p_hostname.is_empty()) {
resolver->cache.clear();
} else {
resolver->cache.erase(_IP_ResolverPrivate::get_cache_key(p_hostname, IP::TYPE_NONE));
@@ -285,26 +285,14 @@ IP::IP() {
singleton = this;
resolver = memnew(_IP_ResolverPrivate);
-#ifndef NO_THREADS
-
resolver->thread_abort = false;
-
- resolver->thread = Thread::create(_IP_ResolverPrivate::_thread_function, resolver);
-#else
- resolver->thread = nullptr;
-#endif
+ resolver->thread.start(_IP_ResolverPrivate::_thread_function, resolver);
}
IP::~IP() {
-#ifndef NO_THREADS
- if (resolver->thread) {
- resolver->thread_abort = true;
- resolver->sem.post();
- Thread::wait_to_finish(resolver->thread);
- memdelete(resolver->thread);
- }
-
-#endif
+ resolver->thread_abort = true;
+ resolver->sem.post();
+ resolver->thread.wait_to_finish();
memdelete(resolver);
}
diff --git a/core/io/ip.h b/core/io/ip.h
index 32572b8eb2..ae080b8e26 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index 7d730e5ae8..5f98eb69e8 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/ip_address.h b/core/io/ip_address.h
index 7a813230f5..49bf83d72f 100644
--- a/core/io/ip_address.h
+++ b/core/io/ip_address.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/json.cpp b/core/io/json.cpp
index d61c2b8236..0d9117fdda 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -47,7 +47,7 @@ const char *JSON::tk_name[TK_MAX] = {
static String _make_indent(const String &p_indent, int p_size) {
String indent_text = "";
- if (!p_indent.empty()) {
+ if (!p_indent.is_empty()) {
for (int i = 0; i < p_size; i++) {
indent_text += p_indent;
}
@@ -59,7 +59,7 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_
String colon = ":";
String end_statement = "";
- if (!p_indent.empty()) {
+ if (!p_indent.is_empty()) {
colon += " ";
end_statement += "\n";
}
@@ -234,6 +234,52 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
}
index += 4; //will add at the end anyway
+ if ((res & 0xfffffc00) == 0xd800) {
+ if (p_str[index + 1] != '\\' || p_str[index + 2] != 'u') {
+ r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
+ return ERR_PARSE_ERROR;
+ }
+ index += 2;
+ char32_t trail = 0;
+ for (int j = 0; j < 4; j++) {
+ char32_t c = p_str[index + j + 1];
+ if (c == 0) {
+ r_err_str = "Unterminated String";
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
+ r_err_str = "Malformed hex constant in string";
+ return ERR_PARSE_ERROR;
+ }
+ char32_t v;
+ if (c >= '0' && c <= '9') {
+ v = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ v = c - 'a';
+ v += 10;
+ } else if (c >= 'A' && c <= 'F') {
+ v = c - 'A';
+ v += 10;
+ } else {
+ ERR_PRINT("Bug parsing hex constant.");
+ v = 0;
+ }
+
+ trail <<= 4;
+ trail |= v;
+ }
+ if ((trail & 0xfffffc00) == 0xdc00) {
+ res = (res << 10UL) + trail - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ index += 4; //will add at the end anyway
+ } else {
+ r_err_str = "Invalid UTF-16 sequence in string, unpaired lead surrogate";
+ return ERR_PARSE_ERROR;
+ }
+ } else if ((res & 0xfffffc00) == 0xdc00) {
+ r_err_str = "Invalid UTF-16 sequence in string, unpaired trail surrogate";
+ return ERR_PARSE_ERROR;
+ }
+
} break;
default: {
res = next;
diff --git a/core/io/json.h b/core/io/json.h
index 431b252e55..537477666e 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index f5cea00f28..8a07459a1d 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -30,6 +30,7 @@
#include "logger.h"
+#include "core/config/project_settings.h"
#include "core/os/dir_access.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
@@ -42,6 +43,12 @@ bool Logger::should_log(bool p_err) {
return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
}
+bool Logger::_flush_stdout_on_print = true;
+
+void Logger::set_flush_stdout_on_print(bool value) {
+ _flush_stdout_on_print = value;
+}
+
void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) {
if (!should_log(true)) {
return;
@@ -201,15 +208,14 @@ void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) {
}
va_end(list_copy);
file->store_buffer((uint8_t *)buf, len);
+
if (len >= static_buf_size) {
Memory::free_static(buf);
}
-#ifdef DEBUG_ENABLED
- const bool need_flush = true;
-#else
- bool need_flush = p_err;
-#endif
- if (need_flush) {
+
+ if (p_err || _flush_stdout_on_print) {
+ // Don't always flush when printing stdout to avoid performance
+ // issues when `print()` is spammed in release builds.
file->flush();
}
}
@@ -228,9 +234,11 @@ void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) {
vfprintf(stderr, p_format, p_list);
} else {
vprintf(p_format, p_list);
-#ifdef DEBUG_ENABLED
- fflush(stdout);
-#endif
+ if (_flush_stdout_on_print) {
+ // Don't always flush when printing stdout to avoid performance
+ // issues when `print()` is spammed in release builds.
+ fflush(stdout);
+ }
}
}
diff --git a/core/io/logger.h b/core/io/logger.h
index 9eaf506c51..a12945911c 100644
--- a/core/io/logger.h
+++ b/core/io/logger.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -41,6 +41,8 @@ class Logger {
protected:
bool should_log(bool p_err);
+ static bool _flush_stdout_on_print;
+
public:
enum ErrorType {
ERR_ERROR,
@@ -49,6 +51,8 @@ public:
ERR_SHADER
};
+ static void set_flush_stdout_on_print(bool value);
+
virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0 = 0;
virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR);
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index db12fcb7f7..218a612da2 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index 6969a9b500..cc0e9ba301 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp
index afab00ebd6..6b550e69c8 100644
--- a/core/io/multiplayer_api.cpp
+++ b/core/io/multiplayer_api.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h
index ca52a1c689..7f88b53a27 100644
--- a/core/io/multiplayer_api.h
+++ b/core/io/multiplayer_api.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/net_socket.cpp b/core/io/net_socket.cpp
index 130a2e245e..b51d26ba83 100644
--- a/core/io/net_socket.cpp
+++ b/core/io/net_socket.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/net_socket.h b/core/io/net_socket.h
index 67d0253985..bc09477693 100644
--- a/core/io/net_socket.h
+++ b/core/io/net_socket.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/networked_multiplayer_peer.cpp
index f521f2bb79..b6af046e77 100644
--- a/core/io/networked_multiplayer_peer.cpp
+++ b/core/io/networked_multiplayer_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/networked_multiplayer_peer.h b/core/io/networked_multiplayer_peer.h
index dc76237f45..7c90f97d88 100644
--- a/core/io/networked_multiplayer_peer.h
+++ b/core/io/networked_multiplayer_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index fbe8fa8a28..a0b97772e6 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packed_data_container.h b/core/io/packed_data_container.h
index 3899c14bb4..7791e21bb3 100644
--- a/core/io/packed_data_container.h
+++ b/core/io/packed_data_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 3da494a8ef..318fd10243 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index a25fa03875..9e03c44750 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp
index 9f6fccc993..bac98e20e7 100644
--- a/core/io/packet_peer_dtls.cpp
+++ b/core/io/packet_peer_dtls.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packet_peer_dtls.h b/core/io/packet_peer_dtls.h
index c2ff4e1a7f..31c52f539f 100644
--- a/core/io/packet_peer_dtls.h
+++ b/core/io/packet_peer_dtls.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 488cfbeaa8..d8d63d976f 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index 9a44a1ebea..4bac6994fc 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp
index 5480d3c535..a0697ca18b 100644
--- a/core/io/pck_packer.cpp
+++ b/core/io/pck_packer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -53,7 +53,7 @@ void PCKPacker::_bind_methods() {
}
Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &p_key, bool p_encrypt_directory) {
- ERR_FAIL_COND_V_MSG((p_key.empty() || !p_key.is_valid_hex_number(false) || p_key.length() != 64), ERR_CANT_CREATE, "Invalid Encryption Key (must be 64 characters long).");
+ ERR_FAIL_COND_V_MSG((p_key.is_empty() || !p_key.is_valid_hex_number(false) || p_key.length() != 64), ERR_CANT_CREATE, "Invalid Encryption Key (must be 64 characters long).");
String _key = p_key.to_lower();
key.resize(32);
diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h
index 56be1b52df..dec8f8748d 100644
--- a/core/io/pck_packer.h
+++ b/core/io/pck_packer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 58ab9a8cde..8560e2abc7 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -52,29 +52,29 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
}
if (path_cache != "") {
- ResourceCache::lock->write_lock();
+ ResourceCache::lock.write_lock();
ResourceCache::resources.erase(path_cache);
- ResourceCache::lock->write_unlock();
+ ResourceCache::lock.write_unlock();
}
path_cache = "";
- ResourceCache::lock->read_lock();
+ ResourceCache::lock.read_lock();
bool has_path = ResourceCache::resources.has(p_path);
- ResourceCache::lock->read_unlock();
+ ResourceCache::lock.read_unlock();
if (has_path) {
if (p_take_over) {
- ResourceCache::lock->write_lock();
+ ResourceCache::lock.write_lock();
Resource **res = ResourceCache::resources.getptr(p_path);
if (res) {
(*res)->set_name("");
}
- ResourceCache::lock->write_unlock();
+ ResourceCache::lock.write_unlock();
} else {
- ResourceCache::lock->read_lock();
+ ResourceCache::lock.read_lock();
bool exists = ResourceCache::resources.has(p_path);
- ResourceCache::lock->read_unlock();
+ ResourceCache::lock.read_unlock();
ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
}
@@ -82,12 +82,11 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
path_cache = p_path;
if (path_cache != "") {
- ResourceCache::lock->write_lock();
+ ResourceCache::lock.write_lock();
ResourceCache::resources[path_cache] = this;
- ResourceCache::lock->write_unlock();
+ ResourceCache::lock.write_unlock();
}
- _change_notify("resource_path");
_resource_path_changed();
}
@@ -105,7 +104,6 @@ int Resource::get_subindex() const {
void Resource::set_name(const String &p_name) {
name = p_name;
- _change_notify("resource_name");
}
String Resource::get_name() const {
@@ -116,20 +114,18 @@ bool Resource::editor_can_reload_from_file() {
return true; //by default yes
}
-void Resource::reload_from_file() {
- String path = get_path();
- if (!path.is_resource_file()) {
- return;
+void Resource::reset_state() {
+}
+Error Resource::copy_from(const Ref<Resource> &p_resource) {
+ ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER);
+ if (get_class() != p_resource->get_class()) {
+ return ERR_INVALID_PARAMETER;
}
- Ref<Resource> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), true);
-
- if (!s.is_valid()) {
- return;
- }
+ reset_state(); //may want to reset state
List<PropertyInfo> pi;
- s->get_property_list(&pi);
+ p_resource->get_property_list(&pi);
for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
@@ -139,8 +135,23 @@ void Resource::reload_from_file() {
continue; //do not change path
}
- set(E->get().name, s->get(E->get().name));
+ set(E->get().name, p_resource->get(E->get().name));
+ }
+ return OK;
+}
+void Resource::reload_from_file() {
+ String path = get_path();
+ if (!path.is_resource_file()) {
+ return;
+ }
+
+ Ref<Resource> s = ResourceLoader::load(ResourceLoader::path_remap(path), get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE);
+
+ if (!s.is_valid()) {
+ return;
}
+
+ copy_from(s);
}
Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Resource>, Ref<Resource>> &remap_cache) {
@@ -315,9 +326,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
return;
}
- if (ResourceCache::lock) {
- ResourceCache::lock->write_lock();
- }
+ ResourceCache::lock.write_lock();
if (p_remapped) {
ResourceLoader::remapped_list.add(&remapped_list);
@@ -325,9 +334,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
ResourceLoader::remapped_list.remove(&remapped_list);
}
- if (ResourceCache::lock) {
- ResourceCache::lock->write_unlock();
- }
+ ResourceCache::lock.write_unlock();
}
bool Resource::is_translation_remapped() const {
@@ -338,38 +345,24 @@ bool Resource::is_translation_remapped() const {
//helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
void Resource::set_id_for_path(const String &p_path, int p_id) {
if (p_id == -1) {
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->write_lock();
- }
+ ResourceCache::path_cache_lock.write_lock();
ResourceCache::resource_path_cache[p_path].erase(get_path());
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->write_unlock();
- }
+ ResourceCache::path_cache_lock.write_unlock();
} else {
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->write_lock();
- }
+ ResourceCache::path_cache_lock.write_lock();
ResourceCache::resource_path_cache[p_path][get_path()] = p_id;
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->write_unlock();
- }
+ ResourceCache::path_cache_lock.write_unlock();
}
}
int Resource::get_id_for_path(const String &p_path) const {
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->read_lock();
- }
+ ResourceCache::path_cache_lock.read_lock();
if (ResourceCache::resource_path_cache[p_path].has(get_path())) {
int result = ResourceCache::resource_path_cache[p_path][get_path()];
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->read_unlock();
- }
+ ResourceCache::path_cache_lock.read_unlock();
return result;
} else {
- if (ResourceCache::path_cache_lock) {
- ResourceCache::path_cache_lock->read_unlock();
- }
+ ResourceCache::path_cache_lock.read_unlock();
return -1;
}
}
@@ -386,6 +379,7 @@ void Resource::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_local_to_scene"), &Resource::is_local_to_scene);
ClassDB::bind_method(D_METHOD("get_local_scene"), &Resource::get_local_scene);
ClassDB::bind_method(D_METHOD("setup_local_to_scene"), &Resource::setup_local_to_scene);
+ ClassDB::bind_method(D_METHOD("emit_changed"), &Resource::emit_changed);
ClassDB::bind_method(D_METHOD("duplicate", "subresources"), &Resource::duplicate, DEFVAL(false));
ADD_SIGNAL(MethodInfo("changed"));
@@ -402,9 +396,9 @@ Resource::Resource() :
Resource::~Resource() {
if (path_cache != "") {
- ResourceCache::lock->write_lock();
+ ResourceCache::lock.write_lock();
ResourceCache::resources.erase(path_cache);
- ResourceCache::lock->write_unlock();
+ ResourceCache::lock.write_unlock();
}
if (owners.size()) {
WARN_PRINT("Resource is still owned.");
@@ -416,18 +410,11 @@ HashMap<String, Resource *> ResourceCache::resources;
HashMap<String, HashMap<String, int>> ResourceCache::resource_path_cache;
#endif
-RWLock *ResourceCache::lock = nullptr;
+RWLock ResourceCache::lock;
#ifdef TOOLS_ENABLED
-RWLock *ResourceCache::path_cache_lock = nullptr;
+RWLock ResourceCache::path_cache_lock;
#endif
-void ResourceCache::setup() {
- lock = RWLock::create();
-#ifdef TOOLS_ENABLED
- path_cache_lock = RWLock::create();
-#endif
-}
-
void ResourceCache::clear() {
if (resources.size()) {
ERR_PRINT("Resources still in use at exit (run with --verbose for details).");
@@ -441,29 +428,25 @@ void ResourceCache::clear() {
}
resources.clear();
- memdelete(lock);
-#ifdef TOOLS_ENABLED
- memdelete(path_cache_lock);
-#endif
}
void ResourceCache::reload_externals() {
}
bool ResourceCache::has(const String &p_path) {
- lock->read_lock();
+ lock.read_lock();
bool b = resources.has(p_path);
- lock->read_unlock();
+ lock.read_unlock();
return b;
}
Resource *ResourceCache::get(const String &p_path) {
- lock->read_lock();
+ lock.read_lock();
Resource **res = resources.getptr(p_path);
- lock->read_unlock();
+ lock.read_unlock();
if (!res) {
return nullptr;
@@ -473,26 +456,26 @@ Resource *ResourceCache::get(const String &p_path) {
}
void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) {
- lock->read_lock();
+ lock.read_lock();
const String *K = nullptr;
while ((K = resources.next(K))) {
Resource *r = resources[*K];
p_resources->push_back(Ref<Resource>(r));
}
- lock->read_unlock();
+ lock.read_unlock();
}
int ResourceCache::get_cached_resource_count() {
- lock->read_lock();
+ lock.read_lock();
int rc = resources.size();
- lock->read_unlock();
+ lock.read_unlock();
return rc;
}
void ResourceCache::dump(const char *p_file, bool p_short) {
#ifdef DEBUG_ENABLED
- lock->read_lock();
+ lock.read_lock();
Map<String, int> type_count;
@@ -529,6 +512,6 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
memdelete(f);
}
- lock->read_unlock();
+ lock.read_unlock();
#endif
}
diff --git a/core/io/resource.h b/core/io/resource.h
index 6e0bd7d7f4..ae18ac0c8a 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -90,6 +90,8 @@ public:
static Node *(*_get_local_scene_func)(); //used by editor
virtual bool editor_can_reload_from_file();
+ virtual void reset_state(); //for resources that use variable amount of properties, either via _validate_property or _get_property_list, this function needs to be implemented to correctly clear state
+ virtual Error copy_from(const Ref<Resource> &p_resource);
virtual void reload_from_file();
void register_owner(Object *p_owner);
@@ -149,16 +151,15 @@ typedef Ref<Resource> RES;
class ResourceCache {
friend class Resource;
friend class ResourceLoader; //need the lock
- static RWLock *lock;
+ static RWLock lock;
static HashMap<String, Resource *> resources;
#ifdef TOOLS_ENABLED
static HashMap<String, HashMap<String, int>> resource_path_cache; // each tscn has a set of resource paths and IDs
- static RWLock *path_cache_lock;
+ static RWLock path_cache_lock;
#endif // TOOLS_ENABLED
friend void unregister_core_types();
static void clear();
friend void register_core_types();
- static void setup();
public:
static void reload_externals();
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index aeb859aabd..fb6ad7d65e 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -261,11 +261,11 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
r_v = v;
} break;
case VARIANT_COLOR: {
- Color v;
- v.r = f->get_real();
- v.g = f->get_real();
- v.b = f->get_real();
- v.a = f->get_real();
+ Color v; // Colors should always be in single-precision.
+ v.r = f->get_float();
+ v.g = f->get_float();
+ v.b = f->get_float();
+ v.a = f->get_float();
r_v = v;
} break;
@@ -313,17 +313,12 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
uint32_t index = f->get_32();
String path = res_path + "::" + itos(index);
- if (use_nocache) {
- if (!internal_index_cache.has(path)) {
- WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
- }
- r_v = internal_index_cache[path];
+ //always use internal cache for loading internal resources
+ if (!internal_index_cache.has(path)) {
+ WARN_PRINT(String("Couldn't load resource (no cache): " + path).utf8().get_data());
+ r_v = Variant();
} else {
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
- WARN_PRINT(String("Couldn't load resource: " + path).utf8().get_data());
- }
- r_v = res;
+ r_v = internal_index_cache[path];
}
} break;
@@ -645,7 +640,7 @@ Error ResourceLoaderBinary::load() {
}
} else {
- Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, local_path);
+ Error err = ResourceLoader::load_threaded_request(path, external_resources[i].type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path);
if (err != OK) {
if (!ResourceLoader::get_abort_on_missing_resources()) {
ResourceLoader::notify_dependency_error(local_path, path, external_resources[i].type);
@@ -675,7 +670,7 @@ Error ResourceLoaderBinary::load() {
path = res_path + "::" + path;
}
- if (!use_nocache) {
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE) {
if (ResourceCache::has(path)) {
//already loaded, don't do anything
stage++;
@@ -684,7 +679,7 @@ Error ResourceLoaderBinary::load() {
}
}
} else {
- if (!use_nocache && !ResourceCache::has(res_path)) {
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) {
path = res_path;
}
}
@@ -695,26 +690,40 @@ Error ResourceLoaderBinary::load() {
String t = get_unicode_string();
- Object *obj = ClassDB::instance(t);
- if (!obj) {
- error = ERR_FILE_CORRUPT;
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
- }
+ RES res;
- Resource *r = Object::cast_to<Resource>(obj);
- if (!r) {
- String obj_class = obj->get_class();
- error = ERR_FILE_CORRUPT;
- memdelete(obj); //bye
- ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
+ //use the existing one
+ Resource *r = ResourceCache::get(path);
+ if (r->get_class() == t) {
+ r->reset_state();
+ res = Ref<Resource>(r);
+ }
}
- RES res = RES(r);
+ if (res.is_null()) {
+ //did not replace
- if (path != String()) {
- r->set_path(path);
+ Object *obj = ClassDB::instance(t);
+ if (!obj) {
+ error = ERR_FILE_CORRUPT;
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + ".");
+ }
+
+ Resource *r = Object::cast_to<Resource>(obj);
+ if (!r) {
+ String obj_class = obj->get_class();
+ error = ERR_FILE_CORRUPT;
+ memdelete(obj); //bye
+ ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + ".");
+ }
+
+ res = RES(r);
+ if (path != String() && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
+ r->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); //if got here because the resource with same path has different type, replace it
+ }
+ r->set_subindex(subindex);
}
- r->set_subindex(subindex);
if (!main) {
internal_index_cache[path] = res;
@@ -961,7 +970,7 @@ ResourceLoaderBinary::~ResourceLoaderBinary() {
}
}
-RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -972,7 +981,7 @@ RES ResourceFormatLoaderBinary::load(const String &p_path, const String &p_origi
ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot open file '" + p_path + "'.");
ResourceLoaderBinary loader;
- loader.use_nocache = p_no_cache;
+ loader.cache_mode = p_cache_mode;
loader.use_sub_threads = p_use_sub_threads;
loader.progress = r_progress;
String path = p_original_path != "" ? p_original_path : p_path;
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 54cddca49e..3592bbdbc4 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -78,7 +78,7 @@ class ResourceLoaderBinary {
Map<String, String> remaps;
Error error = OK;
- bool use_nocache = false;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
friend class ResourceFormatLoaderBinary;
@@ -103,7 +103,7 @@ public:
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index 9b14d2c763..5ca0eb884a 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -116,7 +116,7 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
return OK;
}
-RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatImporter::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
PathAndType pat;
Error err = _get_path_and_type(p_path, pat);
@@ -128,7 +128,7 @@ RES ResourceFormatImporter::load(const String &p_path, const String &p_original_
return RES();
}
- RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_no_cache, r_error, p_use_sub_threads, r_progress);
+ RES res = ResourceLoader::_load(pat.path, p_path, pat.type, p_cache_mode, r_error, p_use_sub_threads, r_progress);
#ifdef TOOLS_ENABLED
if (res.is_valid()) {
@@ -352,6 +352,12 @@ void ResourceFormatImporter::get_importers_for_extension(const String &p_extensi
}
}
+void ResourceFormatImporter::get_importers(List<Ref<ResourceImporter>> *r_importers) {
+ for (int i = 0; i < importers.size(); i++) {
+ r_importers->push_back(importers[i]);
+ }
+}
+
Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const String &p_extension) const {
Ref<ResourceImporter> importer;
float priority = 0;
diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h
index 1b300bf656..91efec5534 100644
--- a/core/io/resource_importer.h
+++ b/core/io/resource_importer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -57,7 +57,7 @@ class ResourceFormatImporter : public ResourceFormatLoader {
public:
static ResourceFormatImporter *get_singleton() { return singleton; }
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const;
@@ -82,6 +82,7 @@ public:
Ref<ResourceImporter> get_importer_by_name(const String &p_name) const;
Ref<ResourceImporter> get_importer_by_extension(const String &p_extension) const;
void get_importers_for_extension(const String &p_extension, List<Ref<ResourceImporter>> *r_importers);
+ void get_importers(List<Ref<ResourceImporter>> *r_importers);
bool are_import_settings_valid(const String &p_path) const;
String get_import_settings_hash() const;
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index a8ca6a817e..8275dd0ad4 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -113,9 +113,9 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
}
}
-RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (get_script_instance() && get_script_instance()->has_method("load")) {
- Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads);
+ Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode);
if (res.get_type() == Variant::INT) {
if (r_error) {
@@ -164,7 +164,7 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<
void ResourceFormatLoader::_bind_methods() {
{
- MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"));
+ MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode"));
info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
ClassDB::add_virtual_method(get_class_static(), info);
}
@@ -174,11 +174,15 @@ void ResourceFormatLoader::_bind_methods() {
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types")));
ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames")));
+
+ BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REUSE);
+ BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
}
///////////////////////////////////
-RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress) {
+RES ResourceLoader::_load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress) {
bool found = false;
// Try all loaders and pick the first match for the type hint
@@ -187,7 +191,7 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c
continue;
}
found = true;
- RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_no_cache);
+ RES res = loader[i]->load(p_path, p_original_path != String() ? p_original_path : p_path, r_error, p_use_sub_threads, r_progress, p_cache_mode);
if (res.is_null()) {
continue;
}
@@ -214,7 +218,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
//this is an actual thread, so wait for Ok fom semaphore
thread_load_semaphore->wait(); //wait until its ok to start loading
}
- load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, false, &load_task.error, load_task.use_sub_threads, &load_task.progress);
+ load_task.resource = _load(load_task.remapped_path, load_task.remapped_path != load_task.local_path ? load_task.local_path : String(), load_task.type_hint, load_task.cache_mode, &load_task.error, load_task.use_sub_threads, &load_task.progress);
load_task.progress = 1.0; //it was fully loaded at this point, so force progress to 1.0
@@ -267,7 +271,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
thread_load_mutex->unlock();
}
-Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, const String &p_source_resource) {
+Error ResourceLoader::load_threaded_request(const String &p_path, const String &p_type_hint, bool p_use_sub_threads, ResourceFormatLoader::CacheMode p_cache_mode, const String &p_source_resource) {
String local_path;
if (p_path.is_rel_path()) {
local_path = "res://" + p_path;
@@ -314,6 +318,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.local_path = local_path;
load_task.type_hint = p_type_hint;
+ load_task.cache_mode = p_cache_mode;
load_task.use_sub_threads = p_use_sub_threads;
{ //must check if resource is already loaded before attempting to load it in a thread
@@ -323,9 +328,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?");
}
//lock first if possible
- if (ResourceCache::lock) {
- ResourceCache::lock->read_lock();
- }
+ ResourceCache::lock.read_lock();
//get ptr
Resource **rptr = ResourceCache::resources.getptr(local_path);
@@ -340,9 +343,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
load_task.progress = 1.0;
}
}
- if (ResourceCache::lock) {
- ResourceCache::lock->read_unlock();
- }
+ ResourceCache::lock.read_unlock();
}
if (p_source_resource != String()) {
@@ -366,7 +367,8 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
print_lt("REQUEST: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
- load_task.thread = Thread::create(_thread_load_function, &thread_load_tasks[local_path]);
+ load_task.thread = memnew(Thread);
+ load_task.thread->start(_thread_load_function, &thread_load_tasks[local_path]);
load_task.loader_id = load_task.thread->get_id();
}
@@ -493,7 +495,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
if (load_task.requests == 0) {
if (load_task.thread) { //thread may not have been used
- Thread::wait_to_finish(load_task.thread);
+ load_task.thread->wait_to_finish();
memdelete(load_task.thread);
}
thread_load_tasks.erase(local_path);
@@ -504,7 +506,7 @@ RES ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
return resource;
}
-RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) {
+RES ResourceLoader::load(const String &p_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
@@ -516,7 +518,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
local_path = ProjectSettings::get_singleton()->localize_path(p_path);
}
- if (!p_no_cache) {
+ if (p_cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) {
thread_load_mutex->lock();
//Is it already being loaded? poll until done
@@ -535,9 +537,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
}
//Is it cached?
- if (ResourceCache::lock) {
- ResourceCache::lock->read_lock();
- }
+ ResourceCache::lock.read_lock();
Resource **rptr = ResourceCache::resources.getptr(local_path);
@@ -546,9 +546,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
//it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
if (res.is_valid()) {
- if (ResourceCache::lock) {
- ResourceCache::lock->read_unlock();
- }
+ ResourceCache::lock.read_unlock();
thread_load_mutex->unlock();
if (r_error) {
@@ -559,9 +557,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
}
}
- if (ResourceCache::lock) {
- ResourceCache::lock->read_unlock();
- }
+ ResourceCache::lock.read_unlock();
//load using task (but this thread)
ThreadLoadTask load_task;
@@ -570,6 +566,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
load_task.local_path = local_path;
load_task.remapped_path = _path_remap(local_path, &load_task.xl_remapped);
load_task.type_hint = p_type_hint;
+ load_task.cache_mode = p_cache_mode; //ignore
load_task.loader_id = Thread::get_caller_id();
thread_load_tasks[local_path] = load_task;
@@ -590,7 +587,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p
print_verbose("Loading resource: " + path);
float p;
- RES res = _load(path, local_path, p_type_hint, p_no_cache, r_error, false, &p);
+ RES res = _load(path, local_path, p_type_hint, p_cache_mode, r_error, false, &p);
if (res.is_null()) {
print_verbose("Failed loading resource: " + path);
@@ -955,9 +952,7 @@ String ResourceLoader::path_remap(const String &p_path) {
}
void ResourceLoader::reload_translation_remaps() {
- if (ResourceCache::lock) {
- ResourceCache::lock->read_lock();
- }
+ ResourceCache::lock.read_lock();
List<Resource *> to_reload;
SelfList<Resource> *E = remapped_list.first();
@@ -967,9 +962,7 @@ void ResourceLoader::reload_translation_remaps() {
E = E->next();
}
- if (ResourceCache::lock) {
- ResourceCache::lock->read_unlock();
- }
+ ResourceCache::lock.read_unlock();
//now just make sure to not delete any of these resources while changing locale..
while (to_reload.front()) {
@@ -979,11 +972,11 @@ void ResourceLoader::reload_translation_remaps() {
}
void ResourceLoader::load_translation_remaps() {
- if (!ProjectSettings::get_singleton()->has_setting("locale/translation_remaps")) {
+ if (!ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("locale/translation_remaps");
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
List<Variant> keys;
remaps.get_key_list(&keys);
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 02c668f214..914d988caa 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -38,11 +38,18 @@
class ResourceFormatLoader : public Reference {
GDCLASS(ResourceFormatLoader, Reference);
+public:
+ enum CacheMode {
+ CACHE_MODE_IGNORE, //resource and subresources do not use path cache, no path is set into resource.
+ CACHE_MODE_REUSE, //resource and subresources use patch cache, reuse existing loaded resources instead of loading from disk when available
+ CACHE_MODE_REPLACE, //resource and and subresource use path cache, but replace existing loaded resources when available with information from disk
+ };
+
protected:
static void _bind_methods();
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual bool exists(const String &p_path) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
@@ -59,6 +66,8 @@ public:
virtual ~ResourceFormatLoader() {}
};
+VARIANT_ENUM_CAST(ResourceFormatLoader::CacheMode)
+
typedef void (*ResourceLoadErrorNotify)(void *p_ud, const String &p_text);
typedef void (*DependencyErrorNotify)(void *p_ud, const String &p_loading, const String &p_which, const String &p_type);
@@ -99,7 +108,7 @@ private:
friend class ResourceFormatImporter;
friend class ResourceInteractiveLoader;
//internal load function
- static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, bool p_no_cache, Error *r_error, bool p_use_sub_threads, float *r_progress);
+ static RES _load(const String &p_path, const String &p_original_path, const String &p_type_hint, ResourceFormatLoader::CacheMode p_cache_mode, Error *r_error, bool p_use_sub_threads, float *r_progress);
static ResourceLoadedCallback _loaded_callback;
@@ -114,6 +123,7 @@ private:
String type_hint;
float progress = 0.0;
ThreadLoadStatus status = THREAD_LOAD_IN_PROGRESS;
+ ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE;
Error error = OK;
RES resource;
bool xl_remapped = false;
@@ -136,11 +146,11 @@ private:
static float _dependency_get_progress(const String &p_path);
public:
- static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, const String &p_source_resource = String());
+ static Error load_threaded_request(const String &p_path, const String &p_type_hint = "", bool p_use_sub_threads = false, ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, const String &p_source_resource = String());
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
static RES load_threaded_get(const String &p_path, Error *r_error = nullptr);
- static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = nullptr);
+ static RES load(const String &p_path, const String &p_type_hint = "", ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, Error *r_error = nullptr);
static bool exists(const String &p_path, const String &p_type_hint = "");
static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions);
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 6ded27d82f..7ebc7f34b3 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index c724c4a6e5..2c9e8f1aa3 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index 403f61bb24..8407d55196 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index 8c1e918dd8..dadedbd2dc 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/stream_peer_ssl.cpp b/core/io/stream_peer_ssl.cpp
index daf36a5350..6f5a06474c 100644
--- a/core/io/stream_peer_ssl.cpp
+++ b/core/io/stream_peer_ssl.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/stream_peer_ssl.h b/core/io/stream_peer_ssl.h
index 81b95b856d..1df9ced08c 100644
--- a/core/io/stream_peer_ssl.h
+++ b/core/io/stream_peer_ssl.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index aa9c409528..760710a9eb 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 173f92e2b6..10b90908d4 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
index d7061b6bf4..323d2bbd7f 100644
--- a/core/io/tcp_server.cpp
+++ b/core/io/tcp_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
index eb715a745c..f06ddd2d99 100644
--- a/core/io/tcp_server.h
+++ b/core/io/tcp_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 34cccca540..0e11ff514a 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -70,7 +70,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
is_eof = f->eof_reached();
// If we reached last line and it's not a content line, break, otherwise let processing that last loop
- if (is_eof && l.empty()) {
+ if (is_eof && l.is_empty()) {
if (status == STATUS_READING_ID || status == STATUS_READING_CONTEXT || (status == STATUS_READING_PLURAL && plural_index != plural_forms - 1)) {
memdelete(f);
ERR_FAIL_V_MSG(RES(), "Unexpected EOF while reading PO file at: " + path + ":" + itos(line));
@@ -277,7 +277,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error) {
return translation;
}
-RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) {
+RES TranslationLoaderPO::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index 16c9f1e680..36d33fcac3 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -38,7 +38,7 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
static RES load_translation(FileAccess *f, Error *r_error = nullptr);
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false);
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp
index acd15aadc6..f56fb431ef 100644
--- a/core/io/udp_server.cpp
+++ b/core/io/udp_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index 3175b09b19..bbd2f951c9 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 85143c0f04..1574634aad 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -36,63 +36,6 @@
VARIANT_ENUM_CAST(XMLParser::NodeType);
-static bool _equalsn(const char32_t *str1, const char32_t *str2, int len) {
- int i;
- for (i = 0; i < len && str1[i] && str2[i]; ++i) {
- if (str1[i] != str2[i]) {
- return false;
- }
- }
-
- // if one (or both) of the strings was smaller then they
- // are only equal if they have the same length
- return (i == len) || (str1[i] == 0 && str2[i] == 0);
-}
-
-String XMLParser::_replace_special_characters(const String &origstr) {
- int pos = origstr.find("&");
- int oldPos = 0;
-
- if (pos == -1) {
- return origstr;
- }
-
- String newstr;
-
- while (pos != -1 && pos < origstr.length() - 2) {
- // check if it is one of the special characters
-
- int specialChar = -1;
- for (int i = 0; i < (int)special_characters.size(); ++i) {
- const char32_t *p = &origstr[pos] + 1;
-
- if (_equalsn(&special_characters[i][1], p, special_characters[i].length() - 1)) {
- specialChar = i;
- break;
- }
- }
-
- if (specialChar != -1) {
- newstr += (origstr.substr(oldPos, pos - oldPos));
- newstr += (special_characters[specialChar][0]);
- pos += special_characters[specialChar].length();
- } else {
- newstr += (origstr.substr(oldPos, pos - oldPos + 1));
- pos += 1;
- }
-
- // find next &
- oldPos = pos;
- pos = origstr.find("&", pos);
- }
-
- if (oldPos < origstr.length() - 1) {
- newstr += (origstr.substr(oldPos, origstr.length() - oldPos));
- }
-
- return newstr;
-}
-
static inline bool _is_white_space(char c) {
return (c == ' ' || c == '\t' || c == '\n' || c == '\r');
}
@@ -116,7 +59,7 @@ bool XMLParser::_set_text(char *start, char *end) {
// set current text to the parsed text, and replace xml special characters
String s = String::utf8(start, (int)(end - start));
- node_name = _replace_special_characters(s);
+ node_name = s.xml_unescape();
// current XML node type is text
node_type = NODE_TEXT;
@@ -292,7 +235,7 @@ void XMLParser::_parse_opening_xml_element() {
String s = String::utf8(attributeValueBegin,
(int)(attributeValueEnd - attributeValueBegin));
- attr.value = _replace_special_characters(s);
+ attr.value = s.xml_unescape();
attributes.push_back(attr);
} else {
// tag is closed directly
@@ -555,11 +498,6 @@ int XMLParser::get_current_line() const {
}
XMLParser::XMLParser() {
- special_characters.push_back("&amp;");
- special_characters.push_back("<lt;");
- special_characters.push_back(">gt;");
- special_characters.push_back("\"quot;");
- special_characters.push_back("'apos;");
}
XMLParser::~XMLParser() {
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index d8cc26b4c1..847edf958d 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -68,8 +68,6 @@ private:
char *data = nullptr;
char *P = nullptr;
uint64_t length = 0;
- void unescape(String &p_str);
- Vector<String> special_characters;
String node_name;
bool node_empty = false;
NodeType node_type = NODE_NONE;
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index b8e7fd34d0..4b4a46e198 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
index ba2065b5d1..52691c65e9 100644
--- a/core/io/zip_io.h
+++ b/core/io/zip_io.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index b4410acf7d..88e11a630c 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -35,7 +35,7 @@
#include "scene/scene_string_names.h"
int AStar::get_available_point_id() const {
- if (points.empty()) {
+ if (points.is_empty()) {
return 1;
}
@@ -341,7 +341,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
- while (!open_list.empty()) {
+ while (!open_list.is_empty()) {
Point *p = open_list[0]; // The currently processed point
if (p == end_point) {
@@ -805,7 +805,7 @@ bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) {
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
open_list.push_back(begin_point);
- while (!open_list.empty()) {
+ while (!open_list.is_empty()) {
AStar::Point *p = open_list[0]; // The currently processed point
if (p == end_point) {
diff --git a/core/math/a_star.h b/core/math/a_star.h
index 7cfa73f2c2..4c61abd91c 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 08673d0dd1..2c721997d8 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 45dcbc7f7f..e16246902a 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -107,6 +107,9 @@ public:
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
Variant intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const;
+ _FORCE_INLINE_ void quantize(real_t p_unit);
+ _FORCE_INLINE_ AABB quantized(real_t p_unit) const;
+
_FORCE_INLINE_ void set_end(const Vector3 &p_end) {
size = p_end - position;
}
@@ -190,9 +193,9 @@ Vector3 AABB::get_support(const Vector3 &p_normal) const {
Vector3 ofs = position + half_extents;
return Vector3(
- (p_normal.x > 0) ? -half_extents.x : half_extents.x,
- (p_normal.y > 0) ? -half_extents.y : half_extents.y,
- (p_normal.z > 0) ? -half_extents.z : half_extents.z) +
+ (p_normal.x > 0) ? half_extents.x : -half_extents.x,
+ (p_normal.y > 0) ? half_extents.y : -half_extents.y,
+ (p_normal.z > 0) ? half_extents.z : -half_extents.z) +
ofs;
}
@@ -427,4 +430,28 @@ void AABB::grow_by(real_t p_amount) {
size.z += 2.0 * p_amount;
}
+void AABB::quantize(real_t p_unit) {
+ size += position;
+
+ position.x -= Math::fposmodp(position.x, p_unit);
+ position.y -= Math::fposmodp(position.y, p_unit);
+ position.z -= Math::fposmodp(position.z, p_unit);
+
+ size.x -= Math::fposmodp(size.x, p_unit);
+ size.y -= Math::fposmodp(size.y, p_unit);
+ size.z -= Math::fposmodp(size.z, p_unit);
+
+ size.x += p_unit;
+ size.y += p_unit;
+ size.z += p_unit;
+
+ size -= position;
+}
+
+AABB AABB::quantized(real_t p_unit) const {
+ AABB ret = *this;
+ ret.quantize(p_unit);
+ return ret;
+}
+
#endif // AABB_H
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index 43d4a63cd3..a5616b8d79 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -47,6 +47,9 @@ static inline float undenormalise(volatile float f) {
return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f;
}
+static const float AUDIO_PEAK_OFFSET = 0.0000000001f;
+static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear2db(AUDIO_PEAK_OFFSET)
+
struct AudioFrame {
//left and right samples
float l, r;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index a64f29517d..cbdd8a8c9f 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -790,8 +790,8 @@ Quat Basis::get_quat() const {
temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s);
} else {
int i = m.elements[0][0] < m.elements[1][1] ?
- (m.elements[1][1] < m.elements[2][2] ? 2 : 1) :
- (m.elements[0][0] < m.elements[2][2] ? 2 : 0);
+ (m.elements[1][1] < m.elements[2][2] ? 2 : 1) :
+ (m.elements[0][0] < m.elements[2][2] ? 2 : 0);
int j = (i + 1) % 3;
int k = (i + 2) % 3;
diff --git a/core/math/basis.h b/core/math/basis.h
index 4cb3d55200..56f6227313 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 5e5efb6356..1066cf5e30 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -74,13 +74,22 @@ Plane CameraMatrix::xform4(const Plane &p_vec4) const {
return ret;
}
+void CameraMatrix::adjust_perspective_znear(real_t p_new_znear) {
+ real_t zfar = get_z_far();
+ real_t znear = p_new_znear;
+
+ real_t deltaZ = zfar - znear;
+ matrix[2][2] = -(zfar + znear) / deltaZ;
+ matrix[3][2] = -2 * znear * zfar / deltaZ;
+}
+
void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) {
if (p_flip_fov) {
p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect);
}
real_t sine, cotangent, deltaZ;
- real_t radians = p_fovy_degrees / 2.0 * Math_PI / 180.0;
+ real_t radians = Math::deg2rad(p_fovy_degrees / 2.0);
deltaZ = p_z_far - p_z_near;
sine = Math::sin(radians);
@@ -107,7 +116,7 @@ void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_
real_t left, right, modeltranslation, ymax, xmax, frustumshift;
- ymax = p_z_near * tan(p_fovy_degrees * Math_PI / 360.0f);
+ ymax = p_z_near * tan(Math::deg2rad(p_fovy_degrees / 2.0));
xmax = ymax * p_aspect;
frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;
@@ -655,6 +664,17 @@ real_t CameraMatrix::get_fov() const {
}
}
+float CameraMatrix::get_lod_multiplier() const {
+ if (is_orthogonal()) {
+ return get_viewport_half_extents().x;
+ } else {
+ float zn = get_z_near();
+ float width = get_viewport_half_extents().x * 2.0;
+ return 1.0 / (zn / width);
+ }
+
+ //usage is lod_size / (lod_distance * multiplier) < threshold
+}
void CameraMatrix::make_scale(const Vector3 &p_scale) {
set_identity();
matrix[0][0] = p_scale.x;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index c5cdd98377..3f327d3bc4 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -59,6 +59,7 @@ struct CameraMatrix {
void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false);
void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far);
void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false);
+ void adjust_perspective_znear(real_t p_new_znear);
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
@@ -108,6 +109,8 @@ struct CameraMatrix {
return !(*this == p_cam);
}
+ float get_lod_multiplier() const;
+
CameraMatrix();
CameraMatrix(const Transform &p_transform);
~CameraMatrix();
diff --git a/core/math/color.cpp b/core/math/color.cpp
index 2afe14bd63..8affb07e8c 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -355,6 +355,23 @@ bool Color::html_is_valid(const String &p_color) {
}
Color Color::named(const String &p_name) {
+ int idx = find_named_color(p_name);
+ if (idx == -1) {
+ ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + ".");
+ return Color();
+ }
+ return get_named_color(idx);
+}
+
+Color Color::named(const String &p_name, const Color &p_default) {
+ int idx = find_named_color(p_name);
+ if (idx == -1) {
+ return p_default;
+ }
+ return get_named_color(idx);
+}
+
+int Color::find_named_color(const String &p_name) {
String name = p_name;
// Normalize name
name = name.replace(" ", "");
@@ -367,14 +384,12 @@ Color Color::named(const String &p_name) {
int idx = 0;
while (named_colors[idx].name != nullptr) {
if (name == named_colors[idx].name) {
- return named_colors[idx].color;
+ return idx;
}
idx++;
}
- ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + ".");
-
- return Color();
+ return -1;
}
int Color::get_named_color_count() {
@@ -384,13 +399,25 @@ int Color::get_named_color_count() {
}
return idx;
}
+
String Color::get_named_color_name(int p_idx) {
return named_colors[p_idx].name;
}
+
Color Color::get_named_color(int p_idx) {
return named_colors[p_idx].color;
}
+// For a version that errors on invalid values instead of returning
+// a default color, use the Color(String) constructor instead.
+Color Color::from_string(const String &p_string, const Color &p_default) {
+ if (html_is_valid(p_string)) {
+ return html(p_string);
+ } else {
+ return named(p_string, p_default);
+ }
+}
+
String _to_hex(float p_val) {
int v = Math::round(p_val * 255);
v = CLAMP(v, 0, 255);
@@ -425,56 +452,9 @@ String Color::to_html(bool p_alpha) const {
}
Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const {
- p_h = Math::fmod(p_h * 360.0f, 360.0f);
- if (p_h < 0.0) {
- p_h += 360.0f;
- }
-
- const float h_ = p_h / 60.0f;
- const float c = p_v * p_s;
- const float x = c * (1.0f - Math::abs(Math::fmod(h_, 2.0f) - 1.0f));
- float r, g, b;
-
- switch ((int)h_) {
- case 0: {
- r = c;
- g = x;
- b = 0;
- } break;
- case 1: {
- r = x;
- g = c;
- b = 0;
- } break;
- case 2: {
- r = 0;
- g = c;
- b = x;
- } break;
- case 3: {
- r = 0;
- g = x;
- b = c;
- } break;
- case 4: {
- r = x;
- g = 0;
- b = c;
- } break;
- case 5: {
- r = c;
- g = 0;
- b = x;
- } break;
- default: {
- r = 0;
- g = 0;
- b = 0;
- } break;
- }
-
- const float m = p_v - c;
- return Color(m + r, m + g, m + b, p_a);
+ Color c;
+ c.set_hsv(p_h, p_s, p_v, p_a);
+ return c;
}
Color::operator String() const {
@@ -519,12 +499,12 @@ Color Color::operator*(const Color &p_color) const {
a * p_color.a);
}
-Color Color::operator*(real_t p_rvalue) const {
+Color Color::operator*(float p_scalar) const {
return Color(
- r * p_rvalue,
- g * p_rvalue,
- b * p_rvalue,
- a * p_rvalue);
+ r * p_scalar,
+ g * p_scalar,
+ b * p_scalar,
+ a * p_scalar);
}
void Color::operator*=(const Color &p_color) {
@@ -534,11 +514,11 @@ void Color::operator*=(const Color &p_color) {
a = a * p_color.a;
}
-void Color::operator*=(real_t p_rvalue) {
- r = r * p_rvalue;
- g = g * p_rvalue;
- b = b * p_rvalue;
- a = a * p_rvalue;
+void Color::operator*=(float p_scalar) {
+ r = r * p_scalar;
+ g = g * p_scalar;
+ b = b * p_scalar;
+ a = a * p_scalar;
}
Color Color::operator/(const Color &p_color) const {
@@ -549,12 +529,12 @@ Color Color::operator/(const Color &p_color) const {
a / p_color.a);
}
-Color Color::operator/(real_t p_rvalue) const {
+Color Color::operator/(float p_scalar) const {
return Color(
- r / p_rvalue,
- g / p_rvalue,
- b / p_rvalue,
- a / p_rvalue);
+ r / p_scalar,
+ g / p_scalar,
+ b / p_scalar,
+ a / p_scalar);
}
void Color::operator/=(const Color &p_color) {
@@ -564,18 +544,11 @@ void Color::operator/=(const Color &p_color) {
a = a / p_color.a;
}
-void Color::operator/=(real_t p_rvalue) {
- if (p_rvalue == 0) {
- r = 1.0;
- g = 1.0;
- b = 1.0;
- a = 1.0;
- } else {
- r = r / p_rvalue;
- g = g / p_rvalue;
- b = b / p_rvalue;
- a = a / p_rvalue;
- }
+void Color::operator/=(float p_scalar) {
+ r = r / p_scalar;
+ g = g / p_scalar;
+ b = b / p_scalar;
+ a = a / p_scalar;
}
Color Color::operator-() const {
diff --git a/core/math/color.h b/core/math/color.h
index b928ff8592..5eb8b1119a 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -78,14 +78,14 @@ struct Color {
void operator-=(const Color &p_color);
Color operator*(const Color &p_color) const;
- Color operator*(real_t p_rvalue) const;
+ Color operator*(float p_scalar) const;
void operator*=(const Color &p_color);
- void operator*=(real_t p_rvalue);
+ void operator*=(float p_scalar);
Color operator/(const Color &p_color) const;
- Color operator/(real_t p_rvalue) const;
+ Color operator/(float p_scalar) const;
void operator/=(const Color &p_color);
- void operator/=(real_t p_rvalue);
+ void operator/=(float p_scalar);
bool is_equal_approx(const Color &p_color) const;
@@ -182,9 +182,12 @@ struct Color {
static Color html(const String &p_rgba);
static bool html_is_valid(const String &p_color);
static Color named(const String &p_name);
+ static Color named(const String &p_name, const Color &p_default);
+ static int find_named_color(const String &p_name);
static int get_named_color_count();
static String get_named_color_name(int p_idx);
static Color get_named_color(int p_idx);
+ static Color from_string(const String &p_string, const Color &p_default);
String to_html(bool p_alpha = true) const;
Color from_hsv(float p_h, float p_s, float p_v, float p_a) const;
static Color from_rgbe9995(uint32_t p_rgbe);
@@ -238,6 +241,19 @@ struct Color {
b = p_c.b;
a = p_a;
}
+
+ Color(const String &p_code) {
+ if (html_is_valid(p_code)) {
+ *this = html(p_code);
+ } else {
+ *this = named(p_code);
+ }
+ }
+
+ Color(const String &p_code, float p_a) {
+ *this = Color(p_code);
+ a = p_a;
+ }
};
bool Color::operator<(const Color &p_color) const {
@@ -256,8 +272,8 @@ bool Color::operator<(const Color &p_color) const {
}
}
-_FORCE_INLINE_ Color operator*(real_t p_real, const Color &p_color) {
- return p_color * p_real;
+_FORCE_INLINE_ Color operator*(float p_scalar, const Color &p_color) {
+ return p_color * p_scalar;
}
#endif // COLOR_H
diff --git a/core/math/color_names.inc b/core/math/color_names.inc
index 523c7e3c59..e5b935ea9c 100644
--- a/core/math/color_names.inc
+++ b/core/math/color_names.inc
@@ -156,5 +156,5 @@ static NamedColor named_colors[] = {
{ "whitesmoke", Color(0.96, 0.96, 0.96) },
{ "yellow", Color(1.00, 1.00, 0.00) },
{ "yellowgreen", Color(0.60, 0.80, 0.20) },
- { nullptr, Color(0.60, 0.80, 0.20) },
+ { nullptr, Color() },
};
diff --git a/core/math/delaunay_2d.h b/core/math/delaunay_2d.h
index d637671686..95064e5700 100644
--- a/core/math/delaunay_2d.h
+++ b/core/math/delaunay_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index ea8655cfff..25cc1125db 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/disjoint_set.h b/core/math/disjoint_set.h
index 51b9ce81af..b155412f64 100644
--- a/core/math/disjoint_set.h
+++ b/core/math/disjoint_set.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp
new file mode 100644
index 0000000000..4639a52278
--- /dev/null
+++ b/core/math/dynamic_bvh.cpp
@@ -0,0 +1,431 @@
+/*************************************************************************/
+/* dynamic_bvh.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 "dynamic_bvh.h"
+
+void DynamicBVH::_delete_node(Node *p_node) {
+ node_allocator.free(p_node);
+}
+
+void DynamicBVH::_recurse_delete_node(Node *p_node) {
+ if (!p_node->is_leaf()) {
+ _recurse_delete_node(p_node->childs[0]);
+ _recurse_delete_node(p_node->childs[1]);
+ }
+ if (p_node == bvh_root) {
+ bvh_root = nullptr;
+ }
+ _delete_node(p_node);
+}
+
+DynamicBVH::Node *DynamicBVH::_create_node(Node *p_parent, void *p_data) {
+ Node *node = node_allocator.alloc();
+ node->parent = p_parent;
+ node->data = p_data;
+ return (node);
+}
+
+DynamicBVH::Node *DynamicBVH::_create_node_with_volume(Node *p_parent, const Volume &p_volume, void *p_data) {
+ Node *node = _create_node(p_parent, p_data);
+ node->volume = p_volume;
+ return node;
+}
+
+void DynamicBVH::_insert_leaf(Node *p_root, Node *p_leaf) {
+ if (!bvh_root) {
+ bvh_root = p_leaf;
+ p_leaf->parent = 0;
+ } else {
+ if (!p_root->is_leaf()) {
+ do {
+ p_root = p_root->childs[p_leaf->volume.select_by_proximity(
+ p_root->childs[0]->volume,
+ p_root->childs[1]->volume)];
+ } while (!p_root->is_leaf());
+ }
+ Node *prev = p_root->parent;
+ Node *node = _create_node_with_volume(prev, p_leaf->volume.merge(p_root->volume), 0);
+ if (prev) {
+ prev->childs[p_root->get_index_in_parent()] = node;
+ node->childs[0] = p_root;
+ p_root->parent = node;
+ node->childs[1] = p_leaf;
+ p_leaf->parent = node;
+ do {
+ if (!prev->volume.contains(node->volume)) {
+ prev->volume = prev->childs[0]->volume.merge(prev->childs[1]->volume);
+ } else {
+ break;
+ }
+ node = prev;
+ } while (0 != (prev = node->parent));
+ } else {
+ node->childs[0] = p_root;
+ p_root->parent = node;
+ node->childs[1] = p_leaf;
+ p_leaf->parent = node;
+ bvh_root = node;
+ }
+ }
+}
+
+DynamicBVH::Node *DynamicBVH::_remove_leaf(Node *leaf) {
+ if (leaf == bvh_root) {
+ bvh_root = 0;
+ return (0);
+ } else {
+ Node *parent = leaf->parent;
+ Node *prev = parent->parent;
+ Node *sibling = parent->childs[1 - leaf->get_index_in_parent()];
+ if (prev) {
+ prev->childs[parent->get_index_in_parent()] = sibling;
+ sibling->parent = prev;
+ _delete_node(parent);
+ while (prev) {
+ const Volume pb = prev->volume;
+ prev->volume = prev->childs[0]->volume.merge(prev->childs[1]->volume);
+ if (pb.is_not_equal_to(prev->volume)) {
+ prev = prev->parent;
+ } else
+ break;
+ }
+ return (prev ? prev : bvh_root);
+ } else {
+ bvh_root = sibling;
+ sibling->parent = 0;
+ _delete_node(parent);
+ return (bvh_root);
+ }
+ }
+}
+
+void DynamicBVH::_fetch_leaves(Node *p_root, LocalVector<Node *> &r_leaves, int p_depth) {
+ if (p_root->is_internal() && p_depth) {
+ _fetch_leaves(p_root->childs[0], r_leaves, p_depth - 1);
+ _fetch_leaves(p_root->childs[1], r_leaves, p_depth - 1);
+ _delete_node(p_root);
+ } else {
+ r_leaves.push_back(p_root);
+ }
+}
+
+// Partitions leaves such that leaves[0, n) are on the
+// left of axis, and leaves[n, count) are on the right
+// of axis. returns N.
+int DynamicBVH::_split(Node **leaves, int p_count, const Vector3 &p_org, const Vector3 &p_axis) {
+ int begin = 0;
+ int end = p_count;
+ for (;;) {
+ while (begin != end && leaves[begin]->is_left_of_axis(p_org, p_axis)) {
+ ++begin;
+ }
+
+ if (begin == end) {
+ break;
+ }
+
+ while (begin != end && !leaves[end - 1]->is_left_of_axis(p_org, p_axis)) {
+ --end;
+ }
+
+ if (begin == end) {
+ break;
+ }
+
+ // swap out of place nodes
+ --end;
+ Node *temp = leaves[begin];
+ leaves[begin] = leaves[end];
+ leaves[end] = temp;
+ ++begin;
+ }
+
+ return begin;
+}
+
+DynamicBVH::Volume DynamicBVH::_bounds(Node **leaves, int p_count) {
+ Volume volume = leaves[0]->volume;
+ for (int i = 1, ni = p_count; i < ni; ++i) {
+ volume = volume.merge(leaves[i]->volume);
+ }
+ return (volume);
+}
+
+void DynamicBVH::_bottom_up(Node **leaves, int p_count) {
+ while (p_count > 1) {
+ real_t minsize = Math_INF;
+ int minidx[2] = { -1, -1 };
+ for (int i = 0; i < p_count; ++i) {
+ for (int j = i + 1; j < p_count; ++j) {
+ const real_t sz = leaves[i]->volume.merge(leaves[j]->volume).get_size();
+ if (sz < minsize) {
+ minsize = sz;
+ minidx[0] = i;
+ minidx[1] = j;
+ }
+ }
+ }
+ Node *n[] = { leaves[minidx[0]], leaves[minidx[1]] };
+ Node *p = _create_node_with_volume(nullptr, n[0]->volume.merge(n[1]->volume), nullptr);
+ p->childs[0] = n[0];
+ p->childs[1] = n[1];
+ n[0]->parent = p;
+ n[1]->parent = p;
+ leaves[minidx[0]] = p;
+ leaves[minidx[1]] = leaves[p_count - 1];
+ --p_count;
+ }
+}
+
+DynamicBVH::Node *DynamicBVH::_top_down(Node **leaves, int p_count, int p_bu_threshold) {
+ static const Vector3 axis[] = { Vector3(1, 0, 0), Vector3(0, 1, 0), Vector3(0, 0, 1) };
+
+ ERR_FAIL_COND_V(p_bu_threshold <= 1, nullptr);
+ if (p_count > 1) {
+ if (p_count > p_bu_threshold) {
+ const Volume vol = _bounds(leaves, p_count);
+ const Vector3 org = vol.get_center();
+ int partition;
+ int bestaxis = -1;
+ int bestmidp = p_count;
+ int splitcount[3][2] = { { 0, 0 }, { 0, 0 }, { 0, 0 } };
+ int i;
+ for (i = 0; i < p_count; ++i) {
+ const Vector3 x = leaves[i]->volume.get_center() - org;
+ for (int j = 0; j < 3; ++j) {
+ ++splitcount[j][x.dot(axis[j]) > 0 ? 1 : 0];
+ }
+ }
+ for (i = 0; i < 3; ++i) {
+ if ((splitcount[i][0] > 0) && (splitcount[i][1] > 0)) {
+ const int midp = (int)Math::abs(real_t(splitcount[i][0] - splitcount[i][1]));
+ if (midp < bestmidp) {
+ bestaxis = i;
+ bestmidp = midp;
+ }
+ }
+ }
+ if (bestaxis >= 0) {
+ partition = _split(leaves, p_count, org, axis[bestaxis]);
+ ERR_FAIL_COND_V(partition == 0 || partition == p_count, nullptr);
+ } else {
+ partition = p_count / 2 + 1;
+ }
+
+ Node *node = _create_node_with_volume(nullptr, vol, nullptr);
+ node->childs[0] = _top_down(&leaves[0], partition, p_bu_threshold);
+ node->childs[1] = _top_down(&leaves[partition], p_count - partition, p_bu_threshold);
+ node->childs[0]->parent = node;
+ node->childs[1]->parent = node;
+ return (node);
+ } else {
+ _bottom_up(leaves, p_count);
+ return (leaves[0]);
+ }
+ }
+ return (leaves[0]);
+}
+
+DynamicBVH::Node *DynamicBVH::_node_sort(Node *n, Node *&r) {
+ Node *p = n->parent;
+ ERR_FAIL_COND_V(!n->is_internal(), nullptr);
+ if (p > n) {
+ const int i = n->get_index_in_parent();
+ const int j = 1 - i;
+ Node *s = p->childs[j];
+ Node *q = p->parent;
+ ERR_FAIL_COND_V(n != p->childs[i], nullptr);
+ if (q)
+ q->childs[p->get_index_in_parent()] = n;
+ else
+ r = n;
+ s->parent = n;
+ p->parent = n;
+ n->parent = q;
+ p->childs[0] = n->childs[0];
+ p->childs[1] = n->childs[1];
+ n->childs[0]->parent = p;
+ n->childs[1]->parent = p;
+ n->childs[i] = p;
+ n->childs[j] = s;
+ SWAP(p->volume, n->volume);
+ return (p);
+ }
+ return (n);
+}
+
+void DynamicBVH::clear() {
+ if (bvh_root) {
+ _recurse_delete_node(bvh_root);
+ }
+ lkhd = -1;
+ opath = 0;
+}
+
+void DynamicBVH::optimize_bottom_up() {
+ if (bvh_root) {
+ LocalVector<Node *> leaves;
+ _fetch_leaves(bvh_root, leaves);
+ _bottom_up(&leaves[0], leaves.size());
+ bvh_root = leaves[0];
+ }
+}
+
+void DynamicBVH::optimize_top_down(int bu_threshold) {
+ if (bvh_root) {
+ LocalVector<Node *> leaves;
+ _fetch_leaves(bvh_root, leaves);
+ bvh_root = _top_down(&leaves[0], leaves.size(), bu_threshold);
+ }
+}
+
+void DynamicBVH::optimize_incremental(int passes) {
+ if (passes < 0)
+ passes = total_leaves;
+ if (bvh_root && (passes > 0)) {
+ do {
+ Node *node = bvh_root;
+ unsigned bit = 0;
+ while (node->is_internal()) {
+ node = _node_sort(node, bvh_root)->childs[(opath >> bit) & 1];
+ bit = (bit + 1) & (sizeof(unsigned) * 8 - 1);
+ }
+ _update(node);
+ ++opath;
+ } while (--passes);
+ }
+}
+
+DynamicBVH::ID DynamicBVH::insert(const AABB &p_box, void *p_userdata) {
+ Volume volume;
+ volume.min = p_box.position;
+ volume.max = p_box.position + p_box.size;
+
+ Node *leaf = _create_node_with_volume(nullptr, volume, p_userdata);
+ _insert_leaf(bvh_root, leaf);
+ ++total_leaves;
+
+ ID id;
+ id.node = leaf;
+
+ return id;
+}
+
+void DynamicBVH::_update(Node *leaf, int lookahead) {
+ Node *root = _remove_leaf(leaf);
+ if (root) {
+ if (lookahead >= 0) {
+ for (int i = 0; (i < lookahead) && root->parent; ++i) {
+ root = root->parent;
+ }
+ } else
+ root = bvh_root;
+ }
+ _insert_leaf(root, leaf);
+}
+
+bool DynamicBVH::update(const ID &p_id, const AABB &p_box) {
+ ERR_FAIL_COND_V(!p_id.is_valid(), false);
+ Node *leaf = p_id.node;
+
+ Volume volume;
+ volume.min = p_box.position;
+ volume.max = p_box.position + p_box.size;
+
+ if (leaf->volume.min.is_equal_approx(volume.min) && leaf->volume.max.is_equal_approx(volume.max)) {
+ // noop
+ return false;
+ }
+
+ Node *base = _remove_leaf(leaf);
+ if (base) {
+ if (lkhd >= 0) {
+ for (int i = 0; (i < lkhd) && base->parent; ++i) {
+ base = base->parent;
+ }
+ } else
+ base = bvh_root;
+ }
+ leaf->volume = volume;
+ _insert_leaf(base, leaf);
+ return true;
+}
+
+void DynamicBVH::remove(const ID &p_id) {
+ ERR_FAIL_COND(!p_id.is_valid());
+ Node *leaf = p_id.node;
+ _remove_leaf(leaf);
+ _delete_node(leaf);
+ --total_leaves;
+}
+
+void DynamicBVH::_extract_leaves(Node *p_node, List<ID> *r_elements) {
+ if (p_node->is_internal()) {
+ _extract_leaves(p_node->childs[0], r_elements);
+ _extract_leaves(p_node->childs[1], r_elements);
+ } else {
+ ID id;
+ id.node = p_node;
+ r_elements->push_back(id);
+ }
+}
+
+void DynamicBVH::set_index(uint32_t p_index) {
+ ERR_FAIL_COND(bvh_root != nullptr);
+ index = p_index;
+}
+
+uint32_t DynamicBVH::get_index() const {
+ return index;
+}
+
+void DynamicBVH::get_elements(List<ID> *r_elements) {
+ if (bvh_root) {
+ _extract_leaves(bvh_root, r_elements);
+ }
+}
+
+int DynamicBVH::get_leaf_count() const {
+ return total_leaves;
+}
+int DynamicBVH::get_max_depth() const {
+ if (bvh_root) {
+ int depth = 1;
+ int max_depth = 0;
+ bvh_root->get_max_depth(depth, max_depth);
+ return max_depth;
+ } else {
+ return 0;
+ }
+}
+
+DynamicBVH::~DynamicBVH() {
+ clear();
+}
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
new file mode 100644
index 0000000000..c71db2d24d
--- /dev/null
+++ b/core/math/dynamic_bvh.h
@@ -0,0 +1,468 @@
+/*************************************************************************/
+/* dynamic_bvh.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 DYNAMICBVH_H
+#define DYNAMICBVH_H
+
+#include "core/math/aabb.h"
+#include "core/templates/list.h"
+#include "core/templates/local_vector.h"
+#include "core/templates/paged_allocator.h"
+#include "core/typedefs.h"
+
+// Based on bullet Dbvh
+
+/*
+Bullet Continuous Collision Detection and Physics Library
+Copyright (c) 2003-2013 Erwin Coumans http://bulletphysics.org
+
+This software is provided 'as-is', without any express or implied warranty.
+In no event will the authors be held liable for any damages arising from the use of this software.
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it freely,
+subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source distribution.
+*/
+
+///DynamicBVH implementation by Nathanael Presson
+// The DynamicBVH class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree).
+
+class DynamicBVH {
+ struct Node;
+
+public:
+ struct ID {
+ Node *node = nullptr;
+
+ public:
+ _FORCE_INLINE_ bool is_valid() const { return node != nullptr; }
+ };
+
+private:
+ struct Volume {
+ Vector3 min, max;
+
+ _FORCE_INLINE_ Vector3 get_center() const { return ((min + max) / 2); }
+ _FORCE_INLINE_ Vector3 get_length() const { return (max - min); }
+
+ _FORCE_INLINE_ bool contains(const Volume &a) const {
+ return ((min.x <= a.min.x) &&
+ (min.y <= a.min.y) &&
+ (min.z <= a.min.z) &&
+ (max.x >= a.max.x) &&
+ (max.y >= a.max.y) &&
+ (max.z >= a.max.z));
+ }
+
+ _FORCE_INLINE_ Volume merge(const Volume &b) const {
+ Volume r;
+ for (int i = 0; i < 3; ++i) {
+ if (min[i] < b.min[i])
+ r.min[i] = min[i];
+ else
+ r.min[i] = b.min[i];
+ if (max[i] > b.max[i])
+ r.max[i] = max[i];
+ else
+ r.max[i] = b.max[i];
+ }
+ return r;
+ }
+
+ _FORCE_INLINE_ real_t get_size() const {
+ const Vector3 edges = get_length();
+ return (edges.x * edges.y * edges.z +
+ edges.x + edges.y + edges.z);
+ }
+
+ _FORCE_INLINE_ bool is_not_equal_to(const Volume &b) const {
+ return ((min.x != b.min.x) ||
+ (min.y != b.min.y) ||
+ (min.z != b.min.z) ||
+ (max.x != b.max.x) ||
+ (max.y != b.max.y) ||
+ (max.z != b.max.z));
+ }
+
+ _FORCE_INLINE_ real_t get_proximity_to(const Volume &b) const {
+ const Vector3 d = (min + max) - (b.min + b.max);
+ return (Math::abs(d.x) + Math::abs(d.y) + Math::abs(d.z));
+ }
+
+ _FORCE_INLINE_ int select_by_proximity(const Volume &a, const Volume &b) const {
+ return (get_proximity_to(a) < get_proximity_to(b) ? 0 : 1);
+ }
+
+ //
+ _FORCE_INLINE_ bool intersects(const Volume &b) const {
+ return ((min.x <= b.max.x) &&
+ (max.x >= b.min.x) &&
+ (min.y <= b.max.y) &&
+ (max.y >= b.min.y) &&
+ (min.z <= b.max.z) &&
+ (max.z >= b.min.z));
+ }
+
+ _FORCE_INLINE_ bool intersects_convex(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
+ Vector3 half_extents = (max - min) * 0.5;
+ Vector3 ofs = min + half_extents;
+
+ for (int i = 0; i < p_plane_count; i++) {
+ const Plane &p = p_planes[i];
+ Vector3 point(
+ (p.normal.x > 0) ? -half_extents.x : half_extents.x,
+ (p.normal.y > 0) ? -half_extents.y : half_extents.y,
+ (p.normal.z > 0) ? -half_extents.z : half_extents.z);
+ point += ofs;
+ if (p.is_point_over(point)) {
+ return false;
+ }
+ }
+
+ // Make sure all points in the shape aren't fully separated from the AABB on
+ // each axis.
+ int bad_point_counts_positive[3] = { 0 };
+ int bad_point_counts_negative[3] = { 0 };
+
+ for (int k = 0; k < 3; k++) {
+ for (int i = 0; i < p_point_count; i++) {
+ if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
+ bad_point_counts_positive[k]++;
+ }
+ if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
+ bad_point_counts_negative[k]++;
+ }
+ }
+
+ if (bad_point_counts_negative[k] == p_point_count) {
+ return false;
+ }
+ if (bad_point_counts_positive[k] == p_point_count) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ };
+
+ struct Node {
+ Volume volume;
+ Node *parent = nullptr;
+ union {
+ Node *childs[2];
+ void *data;
+ };
+
+ _FORCE_INLINE_ bool is_leaf() const { return childs[1] == nullptr; }
+ _FORCE_INLINE_ bool is_internal() const { return (!is_leaf()); }
+
+ _FORCE_INLINE_ int get_index_in_parent() const {
+ ERR_FAIL_COND_V(!parent, 0);
+ return (parent->childs[1] == this) ? 1 : 0;
+ }
+ void get_max_depth(int depth, int &maxdepth) {
+ if (is_internal()) {
+ childs[0]->get_max_depth(depth + 1, maxdepth);
+ childs[1]->get_max_depth(depth + 1, maxdepth);
+ } else {
+ maxdepth = MAX(maxdepth, depth);
+ }
+ }
+
+ //
+ int count_leaves() const {
+ if (is_internal())
+ return childs[0]->count_leaves() + childs[1]->count_leaves();
+ else
+ return (1);
+ }
+
+ bool is_left_of_axis(const Vector3 &org, const Vector3 &axis) const {
+ return axis.dot(volume.get_center() - org) <= 0;
+ }
+
+ Node() {
+ childs[0] = nullptr;
+ childs[1] = nullptr;
+ }
+ };
+
+ PagedAllocator<Node> node_allocator;
+ // Fields
+ Node *bvh_root = nullptr;
+ int lkhd = -1;
+ int total_leaves = 0;
+ uint32_t opath = 0;
+ uint32_t index = 0;
+
+ enum {
+ ALLOCA_STACK_SIZE = 128
+ };
+
+ _FORCE_INLINE_ void _delete_node(Node *p_node);
+ void _recurse_delete_node(Node *p_node);
+ _FORCE_INLINE_ Node *_create_node(Node *p_parent, void *p_data);
+ _FORCE_INLINE_ DynamicBVH::Node *_create_node_with_volume(Node *p_parent, const Volume &p_volume, void *p_data);
+ _FORCE_INLINE_ void _insert_leaf(Node *p_root, Node *p_leaf);
+ _FORCE_INLINE_ Node *_remove_leaf(Node *leaf);
+ void _fetch_leaves(Node *p_root, LocalVector<Node *> &r_leaves, int p_depth = -1);
+ static int _split(Node **leaves, int p_count, const Vector3 &p_org, const Vector3 &p_axis);
+ static Volume _bounds(Node **leaves, int p_count);
+ void _bottom_up(Node **leaves, int p_count);
+ Node *_top_down(Node **leaves, int p_count, int p_bu_threshold);
+ Node *_node_sort(Node *n, Node *&r);
+
+ _FORCE_INLINE_ void _update(Node *leaf, int lookahead = -1);
+
+ void _extract_leaves(Node *p_node, List<ID> *r_elements);
+
+ _FORCE_INLINE_ bool _ray_aabb(const Vector3 &rayFrom, const Vector3 &rayInvDirection, const unsigned int raySign[3], const Vector3 bounds[2], real_t &tmin, real_t lambda_min, real_t lambda_max) {
+ real_t tmax, tymin, tymax, tzmin, tzmax;
+ tmin = (bounds[raySign[0]].x - rayFrom.x) * rayInvDirection.x;
+ tmax = (bounds[1 - raySign[0]].x - rayFrom.x) * rayInvDirection.x;
+ tymin = (bounds[raySign[1]].y - rayFrom.y) * rayInvDirection.y;
+ tymax = (bounds[1 - raySign[1]].y - rayFrom.y) * rayInvDirection.y;
+
+ if ((tmin > tymax) || (tymin > tmax))
+ return false;
+
+ if (tymin > tmin)
+ tmin = tymin;
+
+ if (tymax < tmax)
+ tmax = tymax;
+
+ tzmin = (bounds[raySign[2]].z - rayFrom.z) * rayInvDirection.z;
+ tzmax = (bounds[1 - raySign[2]].z - rayFrom.z) * rayInvDirection.z;
+
+ if ((tmin > tzmax) || (tzmin > tmax))
+ return false;
+ if (tzmin > tmin)
+ tmin = tzmin;
+ if (tzmax < tmax)
+ tmax = tzmax;
+ return ((tmin < lambda_max) && (tmax > lambda_min));
+ }
+
+public:
+ // Methods
+ void clear();
+ bool is_empty() const { return (0 == bvh_root); }
+ void optimize_bottom_up();
+ void optimize_top_down(int bu_threshold = 128);
+ void optimize_incremental(int passes);
+ ID insert(const AABB &p_box, void *p_userdata);
+ bool update(const ID &p_id, const AABB &p_box);
+ void remove(const ID &p_id);
+ void get_elements(List<ID> *r_elements);
+
+ int get_leaf_count() const;
+ int get_max_depth() const;
+
+ /* Discouraged, but works as a reference on how it must be used */
+ struct DefaultQueryResult {
+ virtual bool operator()(void *p_data) = 0; //return true whether you want to continue the query
+ virtual ~DefaultQueryResult() {}
+ };
+
+ template <class QueryResult>
+ _FORCE_INLINE_ void aabb_query(const AABB &p_aabb, QueryResult &r_result);
+ template <class QueryResult>
+ _FORCE_INLINE_ void convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result);
+ template <class QueryResult>
+ _FORCE_INLINE_ void ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result);
+
+ void set_index(uint32_t p_index);
+ uint32_t get_index() const;
+
+ ~DynamicBVH();
+};
+
+template <class QueryResult>
+void DynamicBVH::aabb_query(const AABB &p_box, QueryResult &r_result) {
+ if (!bvh_root) {
+ return;
+ }
+
+ Volume volume;
+ volume.min = p_box.position;
+ volume.max = p_box.position + p_box.size;
+
+ const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *));
+ stack[0] = bvh_root;
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+
+ LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
+
+ do {
+ depth--;
+ const Node *n = stack[depth];
+ if (n->volume.intersects(volume)) {
+ if (n->is_internal()) {
+ if (depth > threshold) {
+ if (aux_stack.is_empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ stack[depth++] = n->childs[0];
+ stack[depth++] = n->childs[1];
+ } else {
+ if (r_result(n->data)) {
+ return;
+ }
+ }
+ }
+ } while (depth > 0);
+}
+
+template <class QueryResult>
+void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, QueryResult &r_result) {
+ if (!bvh_root) {
+ return;
+ }
+
+ //generate a volume anyway to improve pre-testing
+ Volume volume;
+ for (int i = 0; i < p_point_count; i++) {
+ if (i == 0) {
+ volume.min = p_points[0];
+ volume.max = p_points[0];
+ } else {
+ volume.min.x = MIN(volume.min.x, p_points[i].x);
+ volume.min.y = MIN(volume.min.y, p_points[i].y);
+ volume.min.z = MIN(volume.min.z, p_points[i].z);
+
+ volume.max.x = MAX(volume.max.x, p_points[i].x);
+ volume.max.y = MAX(volume.max.y, p_points[i].y);
+ volume.max.z = MAX(volume.max.z, p_points[i].z);
+ }
+ }
+
+ const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *));
+ stack[0] = bvh_root;
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+
+ LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
+
+ do {
+ depth--;
+ const Node *n = stack[depth];
+ if (n->volume.intersects(volume) && n->volume.intersects_convex(p_planes, p_plane_count, p_points, p_point_count)) {
+ if (n->is_internal()) {
+ if (depth > threshold) {
+ if (aux_stack.is_empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ stack[depth++] = n->childs[0];
+ stack[depth++] = n->childs[1];
+ } else {
+ if (r_result(n->data)) {
+ return;
+ }
+ }
+ }
+ } while (depth > 0);
+}
+template <class QueryResult>
+void DynamicBVH::ray_query(const Vector3 &p_from, const Vector3 &p_to, QueryResult &r_result) {
+ if (!bvh_root) {
+ return;
+ }
+
+ Vector3 ray_dir = (p_to - p_from);
+ ray_dir.normalize();
+
+ ///what about division by zero? --> just set rayDirection[i] to INF/B3_LARGE_FLOAT
+ Vector3 inv_dir;
+ inv_dir[0] = ray_dir[0] == real_t(0.0) ? real_t(1e20) : real_t(1.0) / ray_dir[0];
+ inv_dir[1] = ray_dir[1] == real_t(0.0) ? real_t(1e20) : real_t(1.0) / ray_dir[1];
+ inv_dir[2] = ray_dir[2] == real_t(0.0) ? real_t(1e20) : real_t(1.0) / ray_dir[2];
+ unsigned int signs[3] = { inv_dir[0] < 0.0, inv_dir[1] < 0.0, inv_dir[2] < 0.0 };
+
+ real_t lambda_max = ray_dir.dot(p_to - p_from);
+
+ Vector3 bounds[2];
+
+ const Node **stack = (const Node **)alloca(ALLOCA_STACK_SIZE * sizeof(const Node *));
+ stack[0] = bvh_root;
+ int32_t depth = 1;
+ int32_t threshold = ALLOCA_STACK_SIZE - 2;
+
+ LocalVector<const Node *> aux_stack; //only used in rare occasions when you run out of alloca memory because tree is too unbalanced. Should correct itself over time.
+
+ do {
+ depth--;
+ const Node *node = stack[depth];
+ bounds[0] = node->volume.min;
+ bounds[1] = node->volume.max;
+ real_t tmin = 1.f, lambda_min = 0.f;
+ unsigned int result1 = false;
+ result1 = _ray_aabb(p_from, inv_dir, signs, bounds, tmin, lambda_min, lambda_max);
+ if (result1) {
+ if (node->is_internal()) {
+ if (depth > threshold) {
+ if (aux_stack.is_empty()) {
+ aux_stack.resize(ALLOCA_STACK_SIZE * 2);
+ copymem(aux_stack.ptr(), stack, ALLOCA_STACK_SIZE * sizeof(const Node *));
+ } else {
+ aux_stack.resize(aux_stack.size() * 2);
+ }
+ stack = aux_stack.ptr();
+ threshold = aux_stack.size() - 2;
+ }
+ stack[depth++] = node->childs[0];
+ stack[depth++] = node->childs[1];
+ } else {
+ if (r_result(node->data)) {
+ return;
+ }
+ }
+ }
+ } while (depth > 0);
+}
+
+#endif // DYNAMICBVH_H
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 29b706a3a9..636ea601c7 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/expression.h b/core/math/expression.h
index 6b34bc6ae8..a6b288ed6e 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index db2bfaa58b..beb0a8e405 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/face3.h b/core/math/face3.h
index fb40e8ab9e..2e86b0a904 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index 4636e1c774..d67be14d33 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -31,7 +31,7 @@
#include "geometry_2d.h"
#include "thirdparty/misc/clipper.hpp"
-#include "thirdparty/misc/triangulator.h"
+#include "thirdparty/misc/polypartition.h"
#define STB_RECT_PACK_IMPLEMENTATION
#include "thirdparty/misc/stb_rect_pack.h"
@@ -39,16 +39,16 @@
Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(Vector<Point2> polygon) {
Vector<Vector<Vector2>> decomp;
- List<TriangulatorPoly> in_poly, out_poly;
+ List<TPPLPoly> in_poly, out_poly;
- TriangulatorPoly inp;
+ TPPLPoly inp;
inp.Init(polygon.size());
for (int i = 0; i < polygon.size(); i++) {
inp.GetPoint(i) = polygon[i];
}
- inp.SetOrientation(TRIANGULATOR_CCW);
+ inp.SetOrientation(TPPL_ORIENTATION_CCW);
in_poly.push_back(inp);
- TriangulatorPartition tpart;
+ TPPLPartition tpart;
if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { // Failed.
ERR_PRINT("Convex decomposing failed!");
return decomp;
@@ -56,8 +56,8 @@ Vector<Vector<Vector2>> Geometry2D::decompose_polygon_in_convex(Vector<Point2> p
decomp.resize(out_poly.size());
int idx = 0;
- for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) {
- TriangulatorPoly &tp = I->get();
+ for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) {
+ TPPLPoly &tp = I->get();
decomp.write[idx].resize(tp.GetNumPoints());
@@ -94,6 +94,10 @@ void Geometry2D::make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_re
// 256x8192 atlas (won't work anywhere).
ERR_FAIL_COND(p_rects.size() == 0);
+ for (int i = 0; i < p_rects.size(); i++) {
+ ERR_FAIL_COND(p_rects[i].width <= 0);
+ ERR_FAIL_COND(p_rects[i].height <= 0);
+ }
Vector<_AtlasWorkRect> wrects;
wrects.resize(p_rects.size());
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 12bad5768e..4b5aef352f 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -145,6 +145,12 @@ public:
return p_segment[0] + n * d; // Inside.
}
+// Disable False Positives in MSVC compiler; we correctly check for 0 here to prevent a division by 0.
+// See: https://github.com/godotengine/godot/pull/44274
+#ifdef _MSC_VER
+#pragma warning(disable : 4723)
+#endif
+
static bool line_intersects_line(const Vector2 &p_from_a, const Vector2 &p_dir_a, const Vector2 &p_from_b, const Vector2 &p_dir_b, Vector2 &r_result) {
// See http://paulbourke.net/geometry/pointlineplane/
@@ -159,6 +165,11 @@ public:
return true;
}
+// Re-enable division by 0 warning
+#ifdef _MSC_VER
+#pragma warning(default : 4723)
+#endif
+
static bool segment_intersects_segment(const Vector2 &p_from_a, const Vector2 &p_to_a, const Vector2 &p_from_b, const Vector2 &p_to_b, Vector2 *r_result) {
Vector2 B = p_to_a - p_from_a;
Vector2 C = p_from_b - p_from_a;
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index ccb6648561..6628b760e0 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -33,7 +33,7 @@
#include "core/string/print_string.h"
#include "thirdparty/misc/clipper.hpp"
-#include "thirdparty/misc/triangulator.h"
+#include "thirdparty/misc/polypartition.h"
void Geometry3D::MeshData::optimize_vertices() {
Map<int, int> vtx_remap;
@@ -775,12 +775,15 @@ Vector<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
}
Vector<Plane> Geometry3D::build_cylinder_planes(real_t p_radius, real_t p_height, int p_sides, Vector3::Axis p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, 3, Vector<Plane>());
+
Vector<Plane> planes;
+ const double sides_step = Math_TAU / p_sides;
for (int i = 0; i < p_sides; i++) {
Vector3 normal;
- normal[(p_axis + 1) % 3] = Math::cos(i * (2.0 * Math_PI) / p_sides);
- normal[(p_axis + 2) % 3] = Math::sin(i * (2.0 * Math_PI) / p_sides);
+ normal[(p_axis + 1) % 3] = Math::cos(i * sides_step);
+ normal[(p_axis + 2) % 3] = Math::sin(i * sides_step);
planes.push_back(Plane(normal, p_radius));
}
@@ -795,6 +798,8 @@ Vector<Plane> Geometry3D::build_cylinder_planes(real_t p_radius, real_t p_height
}
Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p_lons, Vector3::Axis p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, 3, Vector<Plane>());
+
Vector<Plane> planes;
Vector3 axis;
@@ -805,10 +810,11 @@ Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p
axis_neg[(p_axis + 2) % 3] = 1.0;
axis_neg[p_axis] = -1.0;
+ const double lon_step = Math_TAU / p_lons;
for (int i = 0; i < p_lons; i++) {
Vector3 normal;
- normal[(p_axis + 1) % 3] = Math::cos(i * (2.0 * Math_PI) / p_lons);
- normal[(p_axis + 2) % 3] = Math::sin(i * (2.0 * Math_PI) / p_lons);
+ normal[(p_axis + 1) % 3] = Math::cos(i * lon_step);
+ normal[(p_axis + 2) % 3] = Math::sin(i * lon_step);
planes.push_back(Plane(normal, p_radius));
@@ -825,6 +831,8 @@ Vector<Plane> Geometry3D::build_sphere_planes(real_t p_radius, int p_lats, int p
}
Vector<Plane> Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
+ ERR_FAIL_INDEX_V(p_axis, 3, Vector<Plane>());
+
Vector<Plane> planes;
Vector3 axis;
@@ -835,10 +843,11 @@ Vector<Plane> Geometry3D::build_capsule_planes(real_t p_radius, real_t p_height,
axis_neg[(p_axis + 2) % 3] = 1.0;
axis_neg[p_axis] = -1.0;
+ const double sides_step = Math_TAU / p_sides;
for (int i = 0; i < p_sides; i++) {
Vector3 normal;
- normal[(p_axis + 1) % 3] = Math::cos(i * (2.0 * Math_PI) / p_sides);
- normal[(p_axis + 2) % 3] = Math::sin(i * (2.0 * Math_PI) / p_sides);
+ normal[(p_axis + 1) % 3] = Math::cos(i * sides_step);
+ normal[(p_axis + 2) % 3] = Math::sin(i * sides_step);
planes.push_back(Plane(normal, p_radius));
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index f10fbeaaaf..4ef9b4dbe6 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -252,27 +252,34 @@ public:
return true;
}
- static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr) {
+ static inline bool segment_intersects_cylinder(const Vector3 &p_from, const Vector3 &p_to, real_t p_height, real_t p_radius, Vector3 *r_res = nullptr, Vector3 *r_norm = nullptr, int p_cylinder_axis = 2) {
Vector3 rel = (p_to - p_from);
real_t rel_l = rel.length();
if (rel_l < CMP_EPSILON) {
return false; // Both points are the same.
}
+ ERR_FAIL_COND_V(p_cylinder_axis < 0, false);
+ ERR_FAIL_COND_V(p_cylinder_axis > 2, false);
+ Vector3 cylinder_axis;
+ cylinder_axis[p_cylinder_axis] = 1.0;
+
// First check if they are parallel.
Vector3 normal = (rel / rel_l);
- Vector3 crs = normal.cross(Vector3(0, 0, 1));
+ Vector3 crs = normal.cross(cylinder_axis);
real_t crs_l = crs.length();
- Vector3 z_dir;
+ Vector3 axis_dir;
if (crs_l < CMP_EPSILON) {
- z_dir = Vector3(1, 0, 0); // Any x/y vector OK.
+ Vector3 side_axis;
+ side_axis[(p_cylinder_axis + 1) % 3] = 1.0; // Any side axis OK.
+ axis_dir = side_axis;
} else {
- z_dir = crs / crs_l;
+ axis_dir = crs / crs_l;
}
- real_t dist = z_dir.dot(p_from);
+ real_t dist = axis_dir.dot(p_from);
if (dist >= p_radius) {
return false; // Too far away.
@@ -285,10 +292,10 @@ public:
}
Size2 size(Math::sqrt(w2), p_height * 0.5);
- Vector3 x_dir = z_dir.cross(Vector3(0, 0, 1)).normalized();
+ Vector3 side_dir = axis_dir.cross(cylinder_axis).normalized();
- Vector2 from2D(x_dir.dot(p_from), p_from.z);
- Vector2 to2D(x_dir.dot(p_to), p_to.z);
+ Vector2 from2D(side_dir.dot(p_from), p_from[p_cylinder_axis]);
+ Vector2 to2D(side_dir.dot(p_to), p_to[p_cylinder_axis]);
real_t min = 0, max = 1;
@@ -335,10 +342,12 @@ public:
Vector3 res_normal = result;
if (axis == 0) {
- res_normal.z = 0;
+ res_normal[p_cylinder_axis] = 0;
} else {
- res_normal.x = 0;
- res_normal.y = 0;
+ int axis_side = (p_cylinder_axis + 1) % 3;
+ res_normal[axis_side] = 0;
+ axis_side = (axis_side + 1) % 3;
+ res_normal[axis_side] = 0;
}
res_normal.normalize();
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index 4d97f72ebf..df2223fb78 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -83,11 +83,11 @@ enum VAlign {
VALIGN_BOTTOM
};
-enum Margin {
- MARGIN_LEFT,
- MARGIN_TOP,
- MARGIN_RIGHT,
- MARGIN_BOTTOM
+enum Side {
+ SIDE_LEFT,
+ SIDE_TOP,
+ SIDE_RIGHT,
+ SIDE_BOTTOM
};
enum Corner {
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 221c6812c1..0985a727f2 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/math_fieldwise.h b/core/math/math_fieldwise.h
index e8aac0dced..fe44d09900 100644
--- a/core/math/math_fieldwise.h
+++ b/core/math/math_fieldwise.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp
index e57257b442..e92bb9f4aa 100644
--- a/core/math/math_funcs.cpp
+++ b/core/math/math_funcs.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -123,7 +123,7 @@ double Math::ease(double p_x, double p_c) {
}
}
-double Math::stepify(double p_value, double p_step) {
+double Math::snapped(double p_value, double p_step) {
if (p_step != 0) {
p_value = Math::floor(p_value / p_step + 0.5) * p_step;
}
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 827637bf2b..267f6a4fe2 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -198,6 +198,23 @@ public:
value += 0.0;
return value;
}
+ static _ALWAYS_INLINE_ float fposmodp(float p_x, float p_y) {
+ float value = Math::fmod(p_x, p_y);
+ if (value < 0) {
+ value += p_y;
+ }
+ value += 0.0;
+ return value;
+ }
+ static _ALWAYS_INLINE_ double fposmodp(double p_x, double p_y) {
+ double value = Math::fmod(p_x, p_y);
+ if (value < 0) {
+ value += p_y;
+ }
+ value += 0.0;
+ return value;
+ }
+
static _ALWAYS_INLINE_ int posmod(int p_x, int p_y) {
int value = p_x % p_y;
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
@@ -206,11 +223,11 @@ public:
return value;
}
- static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * Math_PI / 180.0; }
- static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * Math_PI / 180.0; }
+ static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * (Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (Math_PI / 180.0); }
- static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * 180.0 / Math_PI; }
- static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * 180.0 / Math_PI; }
+ static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * (180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (180.0 / Math_PI); }
static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; }
@@ -275,7 +292,7 @@ public:
static double ease(double p_x, double p_c);
static int step_decimals(double p_step);
static int range_step_decimals(double p_step);
- static double stepify(double p_value, double p_step);
+ static double snapped(double p_value, double p_step);
static double dectime(double p_value, double p_amount, double p_step);
static uint32_t larger_prime(uint32_t p_val);
@@ -455,12 +472,12 @@ public:
}
static _ALWAYS_INLINE_ float snap_scalar(float p_offset, float p_step, float p_target) {
- return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target;
+ return p_step != 0 ? Math::snapped(p_target - p_offset, p_step) + p_offset : p_target;
}
static _ALWAYS_INLINE_ float snap_scalar_separation(float p_offset, float p_step, float p_target, float p_separation) {
if (p_step != 0) {
- float a = Math::stepify(p_target - p_offset, p_step + p_separation) + p_offset;
+ float a = Math::snapped(p_target - p_offset, p_step + p_separation) + p_offset;
float b = a;
if (p_target >= 0) {
b -= p_separation;
diff --git a/core/math/octree.h b/core/math/octree.h
index be1e7d6a61..493a63aa2e 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -572,7 +572,7 @@ bool Octree<T, use_pairs, AL>::_remove_element_from_octant(Element *p_element, O
Octant *parent = p_octant->parent;
- if (p_octant->children_count == 0 && p_octant->elements.empty() && p_octant->pairable_elements.empty()) {
+ if (p_octant->children_count == 0 && p_octant->elements.is_empty() && p_octant->pairable_elements.is_empty()) {
// erase octant
if (p_octant == root) { // won't have a parent, just erase
@@ -942,7 +942,7 @@ void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p
return; //pointless
}
- if (!p_octant->elements.empty()) {
+ if (!p_octant->elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->elements.front();
@@ -965,7 +965,7 @@ void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p
}
}
- if (use_pairs && !p_octant->pairable_elements.empty()) {
+ if (use_pairs && !p_octant->pairable_elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->pairable_elements.front();
@@ -1001,7 +1001,7 @@ void Octree<T, use_pairs, AL>::_cull_aabb(Octant *p_octant, const AABB &p_aabb,
return; //pointless
}
- if (!p_octant->elements.empty()) {
+ if (!p_octant->elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->elements.front();
for (; I; I = I->next()) {
@@ -1027,7 +1027,7 @@ void Octree<T, use_pairs, AL>::_cull_aabb(Octant *p_octant, const AABB &p_aabb,
}
}
- if (use_pairs && !p_octant->pairable_elements.empty()) {
+ if (use_pairs && !p_octant->pairable_elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->pairable_elements.front();
for (; I; I = I->next()) {
@@ -1065,7 +1065,7 @@ void Octree<T, use_pairs, AL>::_cull_segment(Octant *p_octant, const Vector3 &p_
return; //pointless
}
- if (!p_octant->elements.empty()) {
+ if (!p_octant->elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->elements.front();
for (; I; I = I->next()) {
@@ -1091,7 +1091,7 @@ void Octree<T, use_pairs, AL>::_cull_segment(Octant *p_octant, const Vector3 &p_
}
}
- if (use_pairs && !p_octant->pairable_elements.empty()) {
+ if (use_pairs && !p_octant->pairable_elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->pairable_elements.front();
for (; I; I = I->next()) {
@@ -1132,7 +1132,7 @@ void Octree<T, use_pairs, AL>::_cull_point(Octant *p_octant, const Vector3 &p_po
return; //pointless
}
- if (!p_octant->elements.empty()) {
+ if (!p_octant->elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->elements.front();
for (; I; I = I->next()) {
@@ -1158,7 +1158,7 @@ void Octree<T, use_pairs, AL>::_cull_point(Octant *p_octant, const Vector3 &p_po
}
}
- if (use_pairs && !p_octant->pairable_elements.empty()) {
+ if (use_pairs && !p_octant->pairable_elements.is_empty()) {
typename List<Element *, AL>::Element *I;
I = p_octant->pairable_elements.front();
for (; I; I = I->next()) {
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index e1ae3288ed..f1d3bbbd54 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/plane.h b/core/math/plane.h
index 1386b0a2cb..2267b28c53 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index fc2d71c377..a9a21a1ba3 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -33,32 +33,6 @@
#include "core/math/basis.h"
#include "core/string/print_string.h"
-// set_euler_xyz expects a vector containing the Euler angles in the format
-// (ax,ay,az), where ax is the angle of rotation around x axis,
-// and similar for other axes.
-// This implementation uses XYZ convention (Z is the first rotation).
-void Quat::set_euler_xyz(const Vector3 &p_euler) {
- real_t half_a1 = p_euler.x * 0.5;
- real_t half_a2 = p_euler.y * 0.5;
- real_t half_a3 = p_euler.z * 0.5;
-
- // R = X(a1).Y(a2).Z(a3) convention for Euler angles.
- // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-2)
- // a3 is the angle of the first rotation, following the notation in this reference.
-
- real_t cos_a1 = Math::cos(half_a1);
- real_t sin_a1 = Math::sin(half_a1);
- real_t cos_a2 = Math::cos(half_a2);
- real_t sin_a2 = Math::sin(half_a2);
- real_t cos_a3 = Math::cos(half_a3);
- real_t sin_a3 = Math::sin(half_a3);
-
- set(sin_a1 * cos_a2 * cos_a3 + sin_a2 * sin_a3 * cos_a1,
- -sin_a1 * sin_a3 * cos_a2 + sin_a2 * cos_a1 * cos_a3,
- sin_a1 * sin_a2 * cos_a3 + sin_a3 * cos_a1 * cos_a2,
- -sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3);
-}
-
// get_euler_xyz returns a vector containing the Euler angles in the format
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
@@ -68,32 +42,6 @@ Vector3 Quat::get_euler_xyz() const {
return m.get_euler_xyz();
}
-// set_euler_yxz expects a vector containing the Euler angles in the format
-// (ax,ay,az), where ax is the angle of rotation around x axis,
-// and similar for other axes.
-// This implementation uses YXZ convention (Z is the first rotation).
-void Quat::set_euler_yxz(const Vector3 &p_euler) {
- real_t half_a1 = p_euler.y * 0.5;
- real_t half_a2 = p_euler.x * 0.5;
- real_t half_a3 = p_euler.z * 0.5;
-
- // R = Y(a1).X(a2).Z(a3) convention for Euler angles.
- // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
- // a3 is the angle of the first rotation, following the notation in this reference.
-
- real_t cos_a1 = Math::cos(half_a1);
- real_t sin_a1 = Math::sin(half_a1);
- real_t cos_a2 = Math::cos(half_a2);
- real_t sin_a2 = Math::sin(half_a2);
- real_t cos_a3 = Math::cos(half_a3);
- real_t sin_a3 = Math::sin(half_a3);
-
- set(sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3,
- sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3,
- -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3,
- sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3);
-}
-
// get_euler_yxz returns a vector containing the Euler angles in the format
// (ax,ay,az), where ax is the angle of rotation around x axis,
// and similar for other axes.
@@ -107,10 +55,10 @@ Vector3 Quat::get_euler_yxz() const {
}
void Quat::operator*=(const Quat &p_q) {
- set(w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y,
- w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z,
- w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x,
- w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z);
+ x = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y;
+ y = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z;
+ z = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x;
+ w = w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z;
}
Quat Quat::operator*(const Quat &p_q) const {
@@ -233,18 +181,49 @@ Quat::operator String() const {
return String::num(x) + ", " + String::num(y) + ", " + String::num(z) + ", " + String::num(w);
}
-void Quat::set_axis_angle(const Vector3 &axis, const real_t &angle) {
+Quat::Quat(const Vector3 &p_axis, real_t p_angle) {
#ifdef MATH_CHECKS
- ERR_FAIL_COND_MSG(!axis.is_normalized(), "The axis Vector3 must be normalized.");
+ ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized.");
#endif
- real_t d = axis.length();
+ real_t d = p_axis.length();
if (d == 0) {
- set(0, 0, 0, 0);
+ x = 0;
+ y = 0;
+ z = 0;
+ w = 0;
} else {
- real_t sin_angle = Math::sin(angle * 0.5);
- real_t cos_angle = Math::cos(angle * 0.5);
+ real_t sin_angle = Math::sin(p_angle * 0.5);
+ real_t cos_angle = Math::cos(p_angle * 0.5);
real_t s = sin_angle / d;
- set(axis.x * s, axis.y * s, axis.z * s,
- cos_angle);
+ x = p_axis.x * s;
+ y = p_axis.y * s;
+ z = p_axis.z * s;
+ w = cos_angle;
}
}
+
+// Euler constructor expects a vector containing the Euler angles in the format
+// (ax, ay, az), where ax is the angle of rotation around x axis,
+// and similar for other axes.
+// This implementation uses YXZ convention (Z is the first rotation).
+Quat::Quat(const Vector3 &p_euler) {
+ real_t half_a1 = p_euler.y * 0.5;
+ real_t half_a2 = p_euler.x * 0.5;
+ real_t half_a3 = p_euler.z * 0.5;
+
+ // R = Y(a1).X(a2).Z(a3) convention for Euler angles.
+ // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
+ // a3 is the angle of the first rotation, following the notation in this reference.
+
+ real_t cos_a1 = Math::cos(half_a1);
+ real_t sin_a1 = Math::sin(half_a1);
+ real_t cos_a2 = Math::cos(half_a2);
+ real_t sin_a2 = Math::sin(half_a2);
+ real_t cos_a3 = Math::cos(half_a3);
+ real_t sin_a3 = Math::sin(half_a3);
+
+ x = sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3;
+ y = sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3;
+ z = -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3;
+ w = sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3;
+}
diff --git a/core/math/quat.h b/core/math/quat.h
index bb980f7677..9db914fe52 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -65,19 +65,14 @@ public:
Quat inverse() const;
_FORCE_INLINE_ real_t dot(const Quat &p_q) const;
- void set_euler_xyz(const Vector3 &p_euler);
Vector3 get_euler_xyz() const;
- void set_euler_yxz(const Vector3 &p_euler);
Vector3 get_euler_yxz() const;
-
- void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); };
Vector3 get_euler() const { return get_euler_yxz(); };
Quat slerp(const Quat &p_to, const real_t &p_weight) const;
Quat slerpni(const Quat &p_to, const real_t &p_weight) const;
Quat cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const;
- void set_axis_angle(const Vector3 &axis, const real_t &angle);
_FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
r_angle = 2 * Math::acos(w);
real_t r = ((real_t)1) / Math::sqrt(1 - w * w);
@@ -124,23 +119,19 @@ public:
operator String() const;
- inline void set(real_t p_x, real_t p_y, real_t p_z, real_t p_w) {
- x = p_x;
- y = p_y;
- z = p_z;
- w = p_w;
- }
-
_FORCE_INLINE_ Quat() {}
+
_FORCE_INLINE_ Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) :
x(p_x),
y(p_y),
z(p_z),
w(p_w) {
}
- Quat(const Vector3 &axis, const real_t &angle) { set_axis_angle(axis, angle); }
- Quat(const Vector3 &euler) { set_euler(euler); }
+ Quat(const Vector3 &p_axis, real_t p_angle);
+
+ Quat(const Vector3 &p_euler);
+
Quat(const Quat &p_q) :
x(p_q.x),
y(p_q.y),
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 8dff13c050..ad28967d7a 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h
index 024325c4fc..48ea139cc9 100644
--- a/core/math/quick_hull.h
+++ b/core/math/quick_hull.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/random_number_generator.cpp b/core/math/random_number_generator.cpp
index f045213fb9..b40d010219 100644
--- a/core/math/random_number_generator.cpp
+++ b/core/math/random_number_generator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 7728fd09c0..a396c2b7d7 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp
index e0768b9403..9609620469 100644
--- a/core/math/random_pcg.cpp
+++ b/core/math/random_pcg.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -51,16 +51,8 @@ float RandomPCG::random(float p_from, float p_to) {
}
int RandomPCG::random(int p_from, int p_to) {
- int range;
- int min;
- if (p_to > p_from) {
- range = p_to - p_from + 1;
- min = p_from;
- } else if (p_to < p_from) {
- range = p_from - p_to + 1;
- min = p_to;
- } else { // from == to
+ if (p_from == p_to) {
return p_from;
}
- return rand(range) + min;
+ return rand(abs(p_from - p_to) + 1) + MIN(p_from, p_to);
}
diff --git a/core/math/random_pcg.h b/core/math/random_pcg.h
index 2e257cb5b7..5a03b758ce 100644
--- a/core/math/random_pcg.h
+++ b/core/math/random_pcg.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index 0cc3c4ca0f..60c44999f7 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/rect2.h b/core/math/rect2.h
index b1fe865ba5..512499bdb2 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -123,8 +123,9 @@ struct Rect2 {
_FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
- inline Rect2 clip(const Rect2 &p_rect) const { /// return a clipped rect
+ // Returns the instersection between two Rect2s or an empty Rect2 if there is no intersection
+ inline Rect2 intersection(const Rect2 &p_rect) const {
Rect2 new_rect = p_rect;
if (!intersects(new_rect)) {
@@ -179,26 +180,26 @@ struct Rect2 {
bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
- inline Rect2 grow(real_t p_by) const {
+ inline Rect2 grow(real_t p_amount) const {
Rect2 g = *this;
- g.position.x -= p_by;
- g.position.y -= p_by;
- g.size.width += p_by * 2;
- g.size.height += p_by * 2;
+ g.position.x -= p_amount;
+ g.position.y -= p_amount;
+ g.size.width += p_amount * 2;
+ g.size.height += p_amount * 2;
return g;
}
- inline Rect2 grow_margin(Margin p_margin, real_t p_amount) const {
+ inline Rect2 grow_side(Side p_side, real_t p_amount) const {
Rect2 g = *this;
- g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
- (MARGIN_TOP == p_margin) ? p_amount : 0,
- (MARGIN_RIGHT == p_margin) ? p_amount : 0,
- (MARGIN_BOTTOM == p_margin) ? p_amount : 0);
+ g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
+ (SIDE_TOP == p_side) ? p_amount : 0,
+ (SIDE_RIGHT == p_side) ? p_amount : 0,
+ (SIDE_BOTTOM == p_side) ? p_amount : 0);
return g;
}
- inline Rect2 grow_margin_bind(uint32_t p_margin, real_t p_amount) const {
- return grow_margin(Margin(p_margin), p_amount);
+ inline Rect2 grow_side_bind(uint32_t p_side, real_t p_amount) const {
+ return grow_side(Side(p_side), p_amount);
}
inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const {
@@ -272,7 +273,7 @@ struct Rect2 {
}
//check inside
- Vector2 tg = r.tangent();
+ Vector2 tg = r.orthogonal();
float s = tg.dot(center) - tg.dot(a);
if (s < 0.0) {
side_plus++;
@@ -365,8 +366,9 @@ struct Rect2i {
_FORCE_INLINE_ bool has_no_area() const {
return (size.x <= 0 || size.y <= 0);
}
- inline Rect2i clip(const Rect2i &p_rect) const { /// return a clipped rect
+ // Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection
+ inline Rect2i intersection(const Rect2i &p_rect) const {
Rect2i new_rect = p_rect;
if (!intersects(new_rect)) {
@@ -420,26 +422,26 @@ struct Rect2i {
bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; }
bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; }
- Rect2i grow(int p_by) const {
+ Rect2i grow(int p_amount) const {
Rect2i g = *this;
- g.position.x -= p_by;
- g.position.y -= p_by;
- g.size.width += p_by * 2;
- g.size.height += p_by * 2;
+ g.position.x -= p_amount;
+ g.position.y -= p_amount;
+ g.size.width += p_amount * 2;
+ g.size.height += p_amount * 2;
return g;
}
- inline Rect2i grow_margin(Margin p_margin, int p_amount) const {
+ inline Rect2i grow_side(Side p_side, int p_amount) const {
Rect2i g = *this;
- g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
- (MARGIN_TOP == p_margin) ? p_amount : 0,
- (MARGIN_RIGHT == p_margin) ? p_amount : 0,
- (MARGIN_BOTTOM == p_margin) ? p_amount : 0);
+ g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0,
+ (SIDE_TOP == p_side) ? p_amount : 0,
+ (SIDE_RIGHT == p_side) ? p_amount : 0,
+ (SIDE_BOTTOM == p_side) ? p_amount : 0);
return g;
}
- inline Rect2i grow_margin_bind(uint32_t p_margin, int p_amount) const {
- return grow_margin(Margin(p_margin), p_amount);
+ inline Rect2i grow_side_bind(uint32_t p_side, int p_amount) const {
+ return grow_side(Side(p_side), p_amount);
}
inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const {
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index 733bb4d55e..fab5d124fa 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/transform.h b/core/math/transform.h
index c63dbcb989..1c05dbe554 100644
--- a/core/math/transform.h
+++ b/core/math/transform.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -51,8 +51,8 @@ public:
void rotate(const Vector3 &p_axis, real_t p_phi);
void rotate_basis(const Vector3 &p_axis, real_t p_phi);
- void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up);
- Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const;
+ void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0));
+ Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const;
void scale(const Vector3 &p_scale);
Transform scaled(const Vector3 &p_scale) const;
@@ -144,8 +144,8 @@ _FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const {
_FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const {
Vector3 point = p_plane.normal * p_plane.d;
Vector3 point_dir = point + p_plane.normal;
- xform_inv(point);
- xform_inv(point_dir);
+ point = xform_inv(point);
+ point_dir = xform_inv(point_dir);
Vector3 normal = point_dir - point;
normal.normalize();
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 00e561f973..4a521b96ae 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 342623939e..327d0f244f 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index cfe8422d80..23c0c686a2 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index d719822ec3..1d1dbc114b 100644
--- a/core/math/triangle_mesh.h
+++ b/core/math/triangle_mesh.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp
index 12bd384c6a..0047c0705d 100644
--- a/core/math/triangulate.cpp
+++ b/core/math/triangulate.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/triangulate.h b/core/math/triangulate.h
index c453b77ecf..55dc4e8e7d 100644
--- a/core/math/triangulate.h
+++ b/core/math/triangulate.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index f9c2eeb57d..5129ed336e 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -122,10 +122,10 @@ Vector2 Vector2::project(const Vector2 &p_to) const {
return p_to * (dot(p_to) / p_to.length_squared());
}
-Vector2 Vector2::snapped(const Vector2 &p_by) const {
+Vector2 Vector2::snapped(const Vector2 &p_step) const {
return Vector2(
- Math::stepify(x, p_by.x),
- Math::stepify(y, p_by.y));
+ Math::snapped(x, p_step.x),
+ Math::snapped(y, p_step.y));
}
Vector2 Vector2::clamped(real_t p_len) const {
@@ -211,11 +211,11 @@ Vector2i Vector2i::operator*(const Vector2i &p_v1) const {
return Vector2i(x * p_v1.x, y * p_v1.y);
}
-Vector2i Vector2i::operator*(const int &rvalue) const {
+Vector2i Vector2i::operator*(const int32_t &rvalue) const {
return Vector2i(x * rvalue, y * rvalue);
}
-void Vector2i::operator*=(const int &rvalue) {
+void Vector2i::operator*=(const int32_t &rvalue) {
x *= rvalue;
y *= rvalue;
}
@@ -224,11 +224,11 @@ Vector2i Vector2i::operator/(const Vector2i &p_v1) const {
return Vector2i(x / p_v1.x, y / p_v1.y);
}
-Vector2i Vector2i::operator/(const int &rvalue) const {
+Vector2i Vector2i::operator/(const int32_t &rvalue) const {
return Vector2i(x / rvalue, y / rvalue);
}
-void Vector2i::operator/=(const int &rvalue) {
+void Vector2i::operator/=(const int32_t &rvalue) {
x /= rvalue;
y /= rvalue;
}
@@ -237,11 +237,11 @@ Vector2i Vector2i::operator%(const Vector2i &p_v1) const {
return Vector2i(x % p_v1.x, y % p_v1.y);
}
-Vector2i Vector2i::operator%(const int &rvalue) const {
+Vector2i Vector2i::operator%(const int32_t &rvalue) const {
return Vector2i(x % rvalue, y % rvalue);
}
-void Vector2i::operator%=(const int &rvalue) {
+void Vector2i::operator%=(const int32_t &rvalue) {
x %= rvalue;
y %= rvalue;
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 33f815a39c..81bc71d590 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -134,7 +134,7 @@ struct Vector2 {
}
Vector2 rotated(real_t p_by) const;
- Vector2 tangent() const {
+ Vector2 orthogonal() const {
return Vector2(y, -x);
}
@@ -265,18 +265,18 @@ struct Vector2i {
};
union {
- int x = 0;
- int width;
+ int32_t x = 0;
+ int32_t width;
};
union {
- int y = 0;
- int height;
+ int32_t y = 0;
+ int32_t height;
};
- _FORCE_INLINE_ int &operator[](int p_idx) {
+ _FORCE_INLINE_ int32_t &operator[](int p_idx) {
return p_idx ? y : x;
}
- _FORCE_INLINE_ const int &operator[](int p_idx) const {
+ _FORCE_INLINE_ const int32_t &operator[](int p_idx) const {
return p_idx ? y : x;
}
@@ -286,16 +286,16 @@ struct Vector2i {
void operator-=(const Vector2i &p_v);
Vector2i operator*(const Vector2i &p_v1) const;
- Vector2i operator*(const int &rvalue) const;
- void operator*=(const int &rvalue);
+ Vector2i operator*(const int32_t &rvalue) const;
+ void operator*=(const int32_t &rvalue);
Vector2i operator/(const Vector2i &p_v1) const;
- Vector2i operator/(const int &rvalue) const;
- void operator/=(const int &rvalue);
+ Vector2i operator/(const int32_t &rvalue) const;
+ void operator/=(const int32_t &rvalue);
Vector2i operator%(const Vector2i &p_v1) const;
- Vector2i operator%(const int &rvalue) const;
- void operator%=(const int &rvalue);
+ Vector2i operator%(const int32_t &rvalue) const;
+ void operator%=(const int32_t &rvalue);
Vector2i operator-() const;
bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
@@ -317,10 +317,10 @@ struct Vector2i {
inline Vector2i() {}
inline Vector2i(const Vector2 &p_vec2) {
- x = (int)p_vec2.x;
- y = (int)p_vec2.y;
+ x = (int32_t)p_vec2.x;
+ y = (int32_t)p_vec2.y;
}
- inline Vector2i(int p_x, int p_y) {
+ inline Vector2i(int32_t p_x, int32_t p_y) {
x = p_x;
y = p_y;
}
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 09354d8e79..f0629d3db8 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -60,15 +60,15 @@ int Vector3::max_axis() const {
return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0);
}
-void Vector3::snap(Vector3 p_val) {
- x = Math::stepify(x, p_val.x);
- y = Math::stepify(y, p_val.y);
- z = Math::stepify(z, p_val.z);
+void Vector3::snap(Vector3 p_step) {
+ x = Math::snapped(x, p_step.x);
+ y = Math::snapped(y, p_step.y);
+ z = Math::snapped(z, p_step.z);
}
-Vector3 Vector3::snapped(Vector3 p_val) const {
+Vector3 Vector3::snapped(Vector3 p_step) const {
Vector3 v = *this;
- v.snap(p_val);
+ v.snap(p_step);
return v;
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 5af84377fd..377581bb45 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -110,6 +110,7 @@ struct Vector3 {
_FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const;
_FORCE_INLINE_ real_t angle_to(const Vector3 &p_to) const;
+ _FORCE_INLINE_ real_t signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const;
_FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_to) const;
_FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const;
@@ -230,6 +231,13 @@ real_t Vector3::angle_to(const Vector3 &p_to) const {
return Math::atan2(cross(p_to).length(), dot(p_to));
}
+real_t Vector3::signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const {
+ Vector3 cross_to = cross(p_to);
+ real_t unsigned_angle = Math::atan2(cross_to.length(), dot(p_to));
+ real_t sign = cross_to.dot(p_axis);
+ return (sign < 0) ? -unsigned_angle : unsigned_angle;
+}
+
Vector3 Vector3::direction_to(const Vector3 &p_to) const {
Vector3 ret(p_to.x - x, p_to.y - y, p_to.z - z);
ret.normalize();
@@ -324,48 +332,40 @@ bool Vector3::operator<(const Vector3 &p_v) const {
if (x == p_v.x) {
if (y == p_v.y) {
return z < p_v.z;
- } else {
- return y < p_v.y;
}
- } else {
- return x < p_v.x;
+ return y < p_v.y;
}
+ return x < p_v.x;
}
bool Vector3::operator>(const Vector3 &p_v) const {
if (x == p_v.x) {
if (y == p_v.y) {
return z > p_v.z;
- } else {
- return y > p_v.y;
}
- } else {
- return x > p_v.x;
+ return y > p_v.y;
}
+ return x > p_v.x;
}
bool Vector3::operator<=(const Vector3 &p_v) const {
if (x == p_v.x) {
if (y == p_v.y) {
return z <= p_v.z;
- } else {
- return y < p_v.y;
}
- } else {
- return x < p_v.x;
+ return y < p_v.y;
}
+ return x < p_v.x;
}
bool Vector3::operator>=(const Vector3 &p_v) const {
if (x == p_v.x) {
if (y == p_v.y) {
return z >= p_v.z;
- } else {
- return y > p_v.y;
}
- } else {
- return x > p_v.x;
+ return y > p_v.y;
}
+ return x > p_v.x;
}
_FORCE_INLINE_ Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) {
diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp
index 718a1553a0..167fa3221d 100644
--- a/core/math/vector3i.cpp
+++ b/core/math/vector3i.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 1bfd6d5ab2..b0411fb62e 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/callable_method_pointer.cpp b/core/object/callable_method_pointer.cpp
index 21a917cbd7..2bfaef744d 100644
--- a/core/object/callable_method_pointer.cpp
+++ b/core/object/callable_method_pointer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/callable_method_pointer.h b/core/object/callable_method_pointer.h
index 68990dcb72..115797a00c 100644
--- a/core/object/callable_method_pointer.h
+++ b/core/object/callable_method_pointer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index f5171f60ec..375ad8fae1 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -377,7 +377,7 @@ uint64_t ClassDB::get_api_hash(APIType p_api) {
while ((k = t->method_map.next(k))) {
String name = k->operator String();
- ERR_CONTINUE(name.empty());
+ ERR_CONTINUE(name.is_empty());
if (name[0] == '_') {
continue; // Ignore non-virtual methods that start with an underscore
@@ -983,9 +983,9 @@ void ClassDB::add_property_subgroup(StringName p_class, const String &p_name, co
// NOTE: For implementation simplicity reasons, this method doesn't allow setters to have optional arguments at the end.
void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index) {
- lock->read_lock();
+ lock.read_lock();
ClassInfo *type = classes.getptr(p_class);
- lock->read_unlock();
+ lock.read_unlock();
ERR_FAIL_COND(!type);
@@ -1541,11 +1541,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
return var;
}
-RWLock *ClassDB::lock = nullptr;
-
-void ClassDB::init() {
- lock = RWLock::create();
-}
+RWLock ClassDB::lock;
void ClassDB::cleanup_defaults() {
default_values.clear();
@@ -1568,8 +1564,6 @@ void ClassDB::cleanup() {
classes.clear();
resource_base_extensions.clear();
compat_classes.clear();
-
- memdelete(lock);
}
//
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 94f26da60d..6fd5748dbb 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -146,7 +146,7 @@ public:
return memnew(T);
}
- static RWLock *lock;
+ static RWLock lock;
static HashMap<StringName, ClassInfo> classes;
static HashMap<StringName, StringName> resource_base_extensions;
static HashMap<StringName, StringName> compat_classes;
@@ -387,7 +387,6 @@ public:
static void get_extensions_for_type(const StringName &p_class, List<String> *p_extensions);
static void add_compatibility_class(const StringName &p_class, const StringName &p_fallback);
- static void init();
static void set_current_api(APIType p_api);
static APIType get_current_api();
diff --git a/core/object/message_queue.cpp b/core/object/message_queue.cpp
index f0d6786853..4751c69f1e 100644
--- a/core/object/message_queue.cpp
+++ b/core/object/message_queue.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/message_queue.h b/core/object/message_queue.h
index 2901ab196a..1b8def62d3 100644
--- a/core/object/message_queue.h
+++ b/core/object/message_queue.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index e6652ac09f..9c5ed60708 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index bd308c9630..7cf4f8d4e8 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 681e1188ff..1a9cce49d8 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -506,7 +506,7 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const {
}
void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_value, bool *r_valid) {
- if (p_names.empty()) {
+ if (p_names.is_empty()) {
if (r_valid) {
*r_valid = false;
}
@@ -561,11 +561,11 @@ void Object::set_indexed(const Vector<StringName> &p_names, const Variant &p_val
set(p_names[0], value_stack.back()->get(), r_valid);
value_stack.pop_back();
- ERR_FAIL_COND(!value_stack.empty());
+ ERR_FAIL_COND(!value_stack.is_empty());
}
Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) const {
- if (p_names.empty()) {
+ if (p_names.is_empty()) {
if (r_valid) {
*r_valid = false;
}
@@ -599,7 +599,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
if (!is_class("Script")) { // can still be set, but this is for userfriendlyness
p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT));
}
- if (!metadata.empty()) {
+ if (!metadata.is_empty()) {
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "__meta__", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
if (script_instance && !p_reversed) {
@@ -808,21 +808,6 @@ String Object::to_string() {
return "[" + get_class() + ":" + itos(get_instance_id()) + "]";
}
-void Object::_changed_callback(Object *p_changed, const char *p_prop) {
-}
-
-void Object::add_change_receptor(Object *p_receptor) {
- change_receptors.insert(p_receptor);
-}
-
-void Object::remove_change_receptor(Object *p_receptor) {
- change_receptors.erase(p_receptor);
-}
-
-void Object::property_list_changed_notify() {
- _change_notify();
-}
-
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
//this function is not meant to be used in any of these ways
ERR_FAIL_COND(p_script.is_null());
@@ -856,7 +841,7 @@ void Object::set_script(const Variant &p_script) {
}
}
- _change_notify(); //scripts may add variables, so refresh is desired
+ notify_property_list_changed(); //scripts may add variables, so refresh is desired
emit_signal(CoreStringNames::get_singleton()->script_changed);
}
@@ -1089,7 +1074,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int
}
}
- while (!disconnect_data.empty()) {
+ while (!disconnect_data.is_empty()) {
const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
_disconnect(dd.signal, dd.callable);
@@ -1357,7 +1342,12 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
ERR_FAIL_COND(!target_object);
SignalData *s = signal_map.getptr(p_signal);
- ERR_FAIL_COND_MSG(!s, vformat("Nonexistent signal '%s' in %s.", p_signal, to_string()));
+ if (!s) {
+ bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) ||
+ (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal));
+ ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. signal: '" + p_signal + "', callable: '" + p_callable + "'.");
+ }
+ ERR_FAIL_COND_MSG(!s, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
ERR_FAIL_COND_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), "Disconnecting nonexistent signal '" + p_signal + "', callable: " + p_callable + ".");
@@ -1373,7 +1363,7 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
target_object->connections.erase(slot->cE);
s->slot_map.erase(*p_callable.get_base_comparator());
- if (s->slot_map.empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
+ if (s->slot_map.is_empty() && ClassDB::has_signal(get_class_name(), p_signal)) {
//not user signal, delete
signal_map.erase(p_signal);
}
@@ -1491,6 +1481,10 @@ void Object::clear_internal_resource_paths() {
}
}
+void Object::notify_property_list_changed() {
+ emit_signal(CoreStringNames::get_singleton()->property_list_changed);
+}
+
void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_class"), &Object::get_class);
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
@@ -1557,7 +1551,7 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_block_signals", "enable"), &Object::set_block_signals);
ClassDB::bind_method(D_METHOD("is_blocking_signals"), &Object::is_blocking_signals);
- ClassDB::bind_method(D_METHOD("property_list_changed_notify"), &Object::property_list_changed_notify);
+ ClassDB::bind_method(D_METHOD("notify_property_list_changed"), &Object::notify_property_list_changed);
ClassDB::bind_method(D_METHOD("set_message_translation", "enable"), &Object::set_message_translation);
ClassDB::bind_method(D_METHOD("can_translate_messages"), &Object::can_translate_messages);
@@ -1569,6 +1563,7 @@ void Object::_bind_methods() {
ClassDB::add_virtual_method("Object", MethodInfo("free"), false);
ADD_SIGNAL(MethodInfo("script_changed"));
+ ADD_SIGNAL(MethodInfo("property_list_changed"));
BIND_VMETHOD(MethodInfo("_notification", PropertyInfo(Variant::INT, "what")));
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_set", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value")));
@@ -1732,7 +1727,7 @@ void *Object::get_script_instance_binding(int p_script_language_index) {
if (!_script_instance_bindings[p_script_language_index]) {
void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this);
if (script_data) {
- atomic_increment(&instance_binding_count);
+ instance_binding_count.increment();
_script_instance_bindings[p_script_language_index] = script_data;
}
}
diff --git a/core/object/object.h b/core/object/object.h
index dc004f38a9..029478873d 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -37,6 +37,7 @@
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
#include "core/templates/map.h"
+#include "core/templates/safe_refcount.h"
#include "core/templates/set.h"
#include "core/templates/vmap.h"
#include "core/variant/callable_bind.h"
@@ -125,6 +126,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_KEYING_INCREMENTS = 1 << 25, // Used in inspector to increment property when keyed in animation player
PROPERTY_USAGE_DEFERRED_SET_RESOURCE = 1 << 26, // when loading, the resource for this property can be set at the end of loading
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT = 1 << 27, // For Object properties, instantiate them when creating in editor.
+ PROPERTY_USAGE_EDITOR_BASIC_SETTING = 1 << 28, //for project or editor settings, show when basic settings are selected
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_NETWORK | PROPERTY_USAGE_INTERNATIONALIZED,
@@ -454,7 +456,6 @@ private:
#endif
bool _block_signals = false;
int _predelete_ok = 0;
- Set<Object *> change_receptors;
ObjectID _instance_id;
bool _predelete();
void _postinitialize();
@@ -482,13 +483,11 @@ private:
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
Variant _get_indexed_bind(const NodePath &p_name) const;
- void property_list_changed_notify();
-
_FORCE_INLINE_ void _construct_object(bool p_reference);
friend class Reference;
bool type_is_reference = false;
- uint32_t instance_binding_count = 0;
+ SafeNumeric<uint32_t> instance_binding_count;
void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS];
Object(bool p_reference);
@@ -525,8 +524,6 @@ protected:
static void get_valid_parents_static(List<String> *p_parents);
static void _get_valid_parents_static(List<String> *p_parents);
- virtual void _changed_callback(Object *p_changed, const char *p_prop);
-
//Variant _call_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
//void _call_deferred_bind(const StringName& p_name, const Variant& p_arg1 = Variant(), const Variant& p_arg2 = Variant(), const Variant& p_arg3 = Variant(), const Variant& p_arg4 = Variant());
@@ -556,16 +553,8 @@ public: //should be protected, but bug in clang++
_FORCE_INLINE_ static void register_custom_data_to_otdb() {}
public:
-#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ void _change_notify(const char *p_property = "") {
- _edited = true;
- for (Set<Object *>::Element *E = change_receptors.front(); E; E = E->next()) {
- ((Object *)(E->get()))->_changed_callback(this, p_property);
- }
- }
-#else
- _FORCE_INLINE_ void _change_notify(const char *p_what = "") {}
-#endif
+ void notify_property_list_changed();
+
static void *get_class_ptr_static() {
static int ptr;
return &ptr;
@@ -575,10 +564,6 @@ public:
_FORCE_INLINE_ ObjectID get_instance_id() const { return _instance_id; }
- // this is used for editors
- void add_change_receptor(Object *p_receptor);
- void remove_change_receptor(Object *p_receptor);
-
template <class T>
static T *cast_to(Object *p_object) {
#ifndef NO_SAFE_CAST
diff --git a/core/object/object_id.h b/core/object/object_id.h
index 63b0c27af8..7f2496ad48 100644
--- a/core/object/object_id.h
+++ b/core/object/object_id.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/reference.cpp b/core/object/reference.cpp
index ce95d83dfc..22e4e8a336 100644
--- a/core/object/reference.cpp
+++ b/core/object/reference.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -62,7 +62,7 @@ bool Reference::reference() {
if (get_script_instance()) {
get_script_instance()->refcount_incremented();
}
- if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
+ if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
if (_script_instance_bindings[i]) {
ScriptServer::get_language(i)->refcount_incremented_instance_binding(this);
@@ -83,7 +83,7 @@ bool Reference::unreference() {
bool script_ret = get_script_instance()->refcount_decremented();
die = die && script_ret;
}
- if (instance_binding_count > 0 && !ScriptServer::are_languages_finished()) {
+ if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) {
for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) {
if (_script_instance_bindings[i]) {
bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this);
diff --git a/core/object/reference.h b/core/object/reference.h
index 0eb127f362..d02cb12069 100644
--- a/core/object/reference.h
+++ b/core/object/reference.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 17ac75e19f..42fb0a0caf 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -275,7 +275,15 @@ void ScriptServer::save_global_classes() {
gcarr.push_back(d);
}
- if (gcarr.empty()) {
+ Array old;
+ if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
+ old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ }
+ if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
+ return;
+ }
+
+ if (gcarr.is_empty()) {
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
ProjectSettings::get_singleton()->clear("_global_script_classes");
}
@@ -515,7 +523,7 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c
}
if (owner && owner->get_script_instance() == this) {
- owner->_change_notify();
+ owner->notify_property_list_changed();
}
//change notify
diff --git a/core/object/script_language.h b/core/object/script_language.h
index f5d65cf42d..f9898ccd0c 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 1dcbb0cd6b..e8735e335c 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -30,6 +30,7 @@
#include "undo_redo.h"
+#include "core/io/resource.h"
#include "core/os/os.h"
void UndoRedo::_discard_redo() {
@@ -52,6 +53,23 @@ void UndoRedo::_discard_redo() {
actions.resize(current_action + 1);
}
+bool UndoRedo::_redo(bool p_execute) {
+ ERR_FAIL_COND_V(action_level > 0, false);
+
+ if ((current_action + 1) >= actions.size()) {
+ return false; //nothing to redo
+ }
+
+ current_action++;
+ if (p_execute) {
+ _process_operation_list(actions.write[current_action].do_ops.front());
+ }
+ version++;
+ emit_signal("version_changed");
+
+ return true;
+}
+
void UndoRedo::create_action(const String &p_name, MergeMode p_mode) {
uint32_t ticks = OS::get_singleton()->get_ticks_msec();
@@ -104,8 +122,8 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
do_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
do_op.type = Operation::TYPE_METHOD;
@@ -130,8 +148,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
undo_op.type = Operation::TYPE_METHOD;
@@ -149,8 +167,8 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
do_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
do_op.type = Operation::TYPE_PROPERTY;
@@ -171,8 +189,8 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
undo_op.type = Operation::TYPE_PROPERTY;
@@ -187,8 +205,8 @@ void UndoRedo::add_do_reference(Object *p_object) {
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
do_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- do_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
do_op.type = Operation::TYPE_REFERENCE;
@@ -207,8 +225,8 @@ void UndoRedo::add_undo_reference(Object *p_object) {
Operation undo_op;
undo_op.object = p_object->get_instance_id();
- if (Object::cast_to<Resource>(p_object)) {
- undo_op.resref = Ref<Resource>(Object::cast_to<Resource>(p_object));
+ if (Object::cast_to<Reference>(p_object)) {
+ undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object));
}
undo_op.type = Operation::TYPE_REFERENCE;
@@ -241,7 +259,7 @@ bool UndoRedo::is_committing_action() const {
return committing > 0;
}
-void UndoRedo::commit_action() {
+void UndoRedo::commit_action(bool p_execute) {
ERR_FAIL_COND(action_level <= 0);
action_level--;
if (action_level > 0) {
@@ -254,8 +272,9 @@ void UndoRedo::commit_action() {
}
committing++;
- redo(); // perform action
+ _redo(p_execute); // perform action
committing--;
+
if (callback && actions.size() > 0) {
callback(callback_ud, actions[actions.size() - 1].name);
}
@@ -322,19 +341,7 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
}
bool UndoRedo::redo() {
- ERR_FAIL_COND_V(action_level > 0, false);
-
- if ((current_action + 1) >= actions.size()) {
- return false; //nothing to redo
- }
-
- current_action++;
-
- _process_operation_list(actions.write[current_action].do_ops.front());
- version++;
- emit_signal("version_changed");
-
- return true;
+ return _redo(true);
}
bool UndoRedo::undo() {
@@ -350,6 +357,24 @@ bool UndoRedo::undo() {
return true;
}
+int UndoRedo::get_history_count() {
+ ERR_FAIL_COND_V(action_level > 0, -1);
+
+ return actions.size();
+}
+
+int UndoRedo::get_current_action() {
+ ERR_FAIL_COND_V(action_level > 0, -1);
+
+ return current_action;
+}
+
+String UndoRedo::get_action_name(int p_id) {
+ ERR_FAIL_INDEX_V(p_id, actions.size(), "");
+
+ return actions[p_id].name;
+}
+
void UndoRedo::clear_history(bool p_increase_version) {
ERR_FAIL_COND(action_level > 0);
_discard_redo();
@@ -479,7 +504,7 @@ Variant UndoRedo::_add_undo_method(const Variant **p_args, int p_argcount, Calla
void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode"), &UndoRedo::create_action, DEFVAL(MERGE_DISABLE));
- ClassDB::bind_method(D_METHOD("commit_action"), &UndoRedo::commit_action);
+ ClassDB::bind_method(D_METHOD("commit_action", "execute"), &UndoRedo::commit_action, DEFVAL(true));
ClassDB::bind_method(D_METHOD("is_committing_action"), &UndoRedo::is_committing_action);
{
@@ -504,8 +529,14 @@ void UndoRedo::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &UndoRedo::add_undo_property);
ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference);
ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference);
+
+ ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count);
+ ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action);
+ ClassDB::bind_method(D_METHOD("get_action_name", "id"), &UndoRedo::get_action_name);
ClassDB::bind_method(D_METHOD("clear_history", "increase_version"), &UndoRedo::clear_history, DEFVAL(true));
+
ClassDB::bind_method(D_METHOD("get_current_action_name"), &UndoRedo::get_current_action_name);
+
ClassDB::bind_method(D_METHOD("has_undo"), &UndoRedo::has_undo);
ClassDB::bind_method(D_METHOD("has_redo"), &UndoRedo::has_redo);
ClassDB::bind_method(D_METHOD("get_version"), &UndoRedo::get_version);
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index 68d78e0d7d..a08ca7792f 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -31,8 +31,8 @@
#ifndef UNDO_REDO_H
#define UNDO_REDO_H
-#include "core/io/resource.h"
#include "core/object/class_db.h"
+#include "core/object/reference.h"
class UndoRedo : public Object {
GDCLASS(UndoRedo, Object);
@@ -61,7 +61,7 @@ private:
};
Type type;
- Ref<Resource> resref;
+ Ref<Reference> ref;
ObjectID object;
StringName name;
Variant args[VARIANT_ARG_MAX];
@@ -84,6 +84,7 @@ private:
void _pop_history_tail();
void _process_operation_list(List<Operation>::Element *E);
void _discard_redo();
+ bool _redo(bool p_execute);
CommitNotifyCallback callback = nullptr;
void *callback_ud = nullptr;
@@ -109,11 +110,15 @@ public:
void add_undo_reference(Object *p_object);
bool is_committing_action() const;
- void commit_action();
+ void commit_action(bool p_execute = true);
bool redo();
bool undo();
String get_current_action_name() const;
+
+ int get_history_count();
+ int get_current_action();
+ String get_action_name(int p_id);
void clear_history(bool p_increase_version = true);
bool has_undo();
diff --git a/core/os/copymem.h b/core/os/copymem.h
index 04ea3caeff..6fd559356c 100644
--- a/core/os/copymem.h
+++ b/core/os/copymem.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index 30b1b51b53..b7c3a17ba9 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -170,7 +170,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
curpath = curpath.plus_file(subdirs[i]);
Error err = make_dir(curpath);
if (err != OK && err != ERR_ALREADY_EXISTS) {
- ERR_FAIL_V(err);
+ ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
}
}
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index 17f84d3c52..c49c4cc4b8 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index aa95f06cff..5a3df88619 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 777c82bbd7..1c78204c1d 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index ef341987dc..4b2cafd8fe 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 67c60a2dbe..3ef70e786f 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index 9252ba0840..016d9d0a09 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -34,8 +34,8 @@
void MainLoop::_bind_methods() {
BIND_VMETHOD(MethodInfo("_initialize"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_iteration", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_idle", PropertyInfo(Variant::FLOAT, "delta")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_physics_process", PropertyInfo(Variant::FLOAT, "delta")));
+ BIND_VMETHOD(MethodInfo(Variant::BOOL, "_process", PropertyInfo(Variant::FLOAT, "delta")));
BIND_VMETHOD(MethodInfo("_finalize"));
BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING);
@@ -52,13 +52,13 @@ void MainLoop::_bind_methods() {
ADD_SIGNAL(MethodInfo("on_request_permissions_result", PropertyInfo(Variant::STRING, "permission"), PropertyInfo(Variant::BOOL, "granted")));
};
-void MainLoop::set_init_script(const Ref<Script> &p_init_script) {
- init_script = p_init_script;
+void MainLoop::set_initialize_script(const Ref<Script> &p_initialize_script) {
+ initialize_script = p_initialize_script;
}
-void MainLoop::init() {
- if (init_script.is_valid()) {
- set_script(init_script);
+void MainLoop::initialize() {
+ if (initialize_script.is_valid()) {
+ set_script(initialize_script);
}
if (get_script_instance()) {
@@ -66,23 +66,23 @@ void MainLoop::init() {
}
}
-bool MainLoop::iteration(float p_time) {
+bool MainLoop::physics_process(float p_time) {
if (get_script_instance()) {
- return get_script_instance()->call("_iteration", p_time);
+ return get_script_instance()->call("_physics_process", p_time);
}
return false;
}
-bool MainLoop::idle(float p_time) {
+bool MainLoop::process(float p_time) {
if (get_script_instance()) {
- return get_script_instance()->call("_idle", p_time);
+ return get_script_instance()->call("_process", p_time);
}
return false;
}
-void MainLoop::finish() {
+void MainLoop::finalize() {
if (get_script_instance()) {
get_script_instance()->call("_finalize");
set_script(Variant()); //clear script
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 7bc91fbb83..25a09fe98f 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -39,7 +39,7 @@ class MainLoop : public Object {
GDCLASS(MainLoop, Object);
OBJ_CATEGORY("Main Loop");
- Ref<Script> init_script;
+ Ref<Script> initialize_script;
protected:
static void _bind_methods();
@@ -59,12 +59,12 @@ public:
NOTIFICATION_TEXT_SERVER_CHANGED = 2018,
};
- virtual void init();
- virtual bool iteration(float p_time);
- virtual bool idle(float p_time);
- virtual void finish();
+ virtual void initialize();
+ virtual bool physics_process(float p_time);
+ virtual bool process(float p_time);
+ virtual void finalize();
- void set_init_script(const Ref<Script> &p_init_script);
+ void set_initialize_script(const Ref<Script> &p_initialize_script);
MainLoop() {}
virtual ~MainLoop() {}
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index f2723d13f6..5910cb0e7b 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -60,11 +60,11 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d
#endif
#ifdef DEBUG_ENABLED
-uint64_t Memory::mem_usage = 0;
-uint64_t Memory::max_usage = 0;
+SafeNumeric<uint64_t> Memory::mem_usage;
+SafeNumeric<uint64_t> Memory::max_usage;
#endif
-uint64_t Memory::alloc_count = 0;
+SafeNumeric<uint64_t> Memory::alloc_count;
void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
@@ -77,7 +77,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
ERR_FAIL_COND_V(!mem, nullptr);
- atomic_increment(&alloc_count);
+ alloc_count.increment();
if (prepad) {
uint64_t *s = (uint64_t *)mem;
@@ -86,8 +86,8 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
uint8_t *s8 = (uint8_t *)mem;
#ifdef DEBUG_ENABLED
- atomic_add(&mem_usage, p_bytes);
- atomic_exchange_if_greater(&max_usage, mem_usage);
+ uint64_t new_mem_usage = mem_usage.add(p_bytes);
+ max_usage.exchange_if_greater(new_mem_usage);
#endif
return s8 + PAD_ALIGN;
} else {
@@ -114,10 +114,10 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
#ifdef DEBUG_ENABLED
if (p_bytes > *s) {
- atomic_add(&mem_usage, p_bytes - *s);
- atomic_exchange_if_greater(&max_usage, mem_usage);
+ uint64_t new_mem_usage = mem_usage.add(p_bytes - *s);
+ max_usage.exchange_if_greater(new_mem_usage);
} else {
- atomic_sub(&mem_usage, *s - p_bytes);
+ mem_usage.sub(*s - p_bytes);
}
#endif
@@ -156,14 +156,14 @@ void Memory::free_static(void *p_ptr, bool p_pad_align) {
bool prepad = p_pad_align;
#endif
- atomic_decrement(&alloc_count);
+ alloc_count.decrement();
if (prepad) {
mem -= PAD_ALIGN;
#ifdef DEBUG_ENABLED
uint64_t *s = (uint64_t *)mem;
- atomic_sub(&mem_usage, *s);
+ mem_usage.sub(*s);
#endif
free(mem);
@@ -178,7 +178,7 @@ uint64_t Memory::get_mem_available() {
uint64_t Memory::get_mem_usage() {
#ifdef DEBUG_ENABLED
- return mem_usage;
+ return mem_usage.get();
#else
return 0;
#endif
@@ -186,7 +186,7 @@ uint64_t Memory::get_mem_usage() {
uint64_t Memory::get_mem_max_usage() {
#ifdef DEBUG_ENABLED
- return max_usage;
+ return max_usage.get();
#else
return 0;
#endif
diff --git a/core/os/memory.h b/core/os/memory.h
index dee08d4de4..10e678103d 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -43,11 +43,11 @@
class Memory {
Memory();
#ifdef DEBUG_ENABLED
- static uint64_t mem_usage;
- static uint64_t max_usage;
+ static SafeNumeric<uint64_t> mem_usage;
+ static SafeNumeric<uint64_t> max_usage;
#endif
- static uint64_t alloc_count;
+ static SafeNumeric<uint64_t> alloc_count;
public:
static void *alloc_static(size_t p_bytes, bool p_pad_align = false);
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index e9919aeb86..a8be84c56c 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h
index f487b31d4c..ccf624e07e 100644
--- a/core/os/midi_driver.h
+++ b/core/os/midi_driver.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp
index 31a0dc2bfa..b7d7752d35 100644
--- a/core/os/mutex.cpp
+++ b/core/os/mutex.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/mutex.h b/core/os/mutex.h
index 778bdaba09..d77ec362a1 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 9400565484..182bab4058 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/os.h b/core/os/os.h
index 3c79d7bb87..e41d788e12 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,6 +40,7 @@
#include "core/templates/vector.h"
#include <stdarg.h>
+#include <stdlib.h>
class OS {
static OS *singleton;
@@ -53,7 +54,7 @@ class OS {
bool _debug_stdout = false;
String _local_clipboard;
bool _no_window = false;
- int _exit_code = 0;
+ int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure
int _orientation;
bool _allow_hidpi = false;
bool _allow_layered = false;
@@ -129,7 +130,8 @@ public:
virtual int get_low_processor_usage_mode_sleep_usec() const;
virtual String get_executable_path() const;
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
+ virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0;
+ virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) = 0;
virtual Error kill(const ProcessID &p_pid) = 0;
virtual int get_process_id() const;
virtual void vibrate_handheld(int p_duration_ms = 500);
@@ -148,11 +150,6 @@ public:
bool is_layered_allowed() const { return _allow_layered; }
bool is_hidpi_allowed() const { return _allow_hidpi; }
- virtual int get_tablet_driver_count() const { return 0; };
- virtual String get_tablet_driver_name(int p_driver) const { return ""; };
- virtual String get_current_tablet_driver() const { return ""; };
- virtual void set_current_tablet_driver(const String &p_driver){};
-
void ensure_user_data_dir();
virtual MainLoop *get_main_loop() const = 0;
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index 52536ff45d..b538ca0c96 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/pool_allocator.h b/core/os/pool_allocator.h
index c67b4d7fa2..15e50dac90 100644
--- a/core/os/pool_allocator.h
+++ b/core/os/pool_allocator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/rw_lock.cpp b/core/os/rw_lock.cpp
deleted file mode 100644
index 669f05c6b0..0000000000
--- a/core/os/rw_lock.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*************************************************************************/
-/* rw_lock.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "rw_lock.h"
-
-#include "core/error/error_macros.h"
-
-#include <stddef.h>
-
-RWLock *(*RWLock::create_func)() = nullptr;
-
-RWLock *RWLock::create() {
- ERR_FAIL_COND_V(!create_func, nullptr);
-
- return create_func();
-}
diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h
index 1190102a83..560ec57a5f 100644
--- a/core/os/rw_lock.h
+++ b/core/os/rw_lock.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -33,55 +33,83 @@
#include "core/error/error_list.h"
+#if !defined(NO_THREADS)
+
+#include <shared_mutex>
+
class RWLock {
-protected:
- static RWLock *(*create_func)();
+ mutable std::shared_timed_mutex mutex;
public:
- virtual void read_lock() = 0; ///< Lock the rwlock, block if locked by someone else
- virtual void read_unlock() = 0; ///< Unlock the rwlock, let other threads continue
- virtual Error read_try_lock() = 0; ///< Attempt to lock the rwlock, OK on success, ERROR means it can't lock.
+ // Lock the rwlock, block if locked by someone else
+ void read_lock() const {
+ mutex.lock_shared();
+ }
- virtual void write_lock() = 0; ///< Lock the rwlock, block if locked by someone else
- virtual void write_unlock() = 0; ///< Unlock the rwlock, let other thwrites continue
- virtual Error write_try_lock() = 0; ///< Attempt to lock the rwlock, OK on success, ERROR means it can't lock.
+ // Unlock the rwlock, let other threads continue
+ void read_unlock() const {
+ mutex.unlock_shared();
+ }
- static RWLock *create(); ///< Create a rwlock
+ // Attempt to lock the rwlock, OK on success, ERR_BUSY means it can't lock.
+ Error read_try_lock() const {
+ return mutex.try_lock_shared() ? OK : ERR_BUSY;
+ }
+
+ // Lock the rwlock, block if locked by someone else
+ void write_lock() {
+ mutex.lock();
+ }
+
+ // Unlock the rwlock, let other thwrites continue
+ void write_unlock() {
+ mutex.unlock();
+ }
- virtual ~RWLock() {}
+ // Attempt to lock the rwlock, OK on success, ERR_BUSY means it can't lock.
+ Error write_try_lock() {
+ return mutex.try_lock() ? OK : ERR_BUSY;
+ }
+};
+
+#else
+
+class RWLock {
+public:
+ void read_lock() const {}
+ void read_unlock() const {}
+ Error read_try_lock() const { return OK; }
+
+ void write_lock() {}
+ void write_unlock() {}
+ Error write_try_lock() { return OK; }
};
+#endif
+
class RWLockRead {
- RWLock *lock;
+ const RWLock &lock;
public:
- RWLockRead(const RWLock *p_lock) {
- lock = const_cast<RWLock *>(p_lock);
- if (lock) {
- lock->read_lock();
- }
+ RWLockRead(const RWLock &p_lock) :
+ lock(p_lock) {
+ lock.read_lock();
}
~RWLockRead() {
- if (lock) {
- lock->read_unlock();
- }
+ lock.read_unlock();
}
};
class RWLockWrite {
- RWLock *lock;
+ RWLock &lock;
public:
- RWLockWrite(RWLock *p_lock) {
- lock = p_lock;
- if (lock) {
- lock->write_lock();
- }
+ RWLockWrite(RWLock &p_lock) :
+ lock(p_lock) {
+ lock.write_lock();
}
~RWLockWrite() {
- if (lock) {
- lock->write_unlock();
- }
+ lock.write_unlock();
}
};
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index b170cada3a..01ae7a3c65 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/spin_lock.h b/core/os/spin_lock.h
index 1bb810bb29..929e8b9a58 100644
--- a/core/os/spin_lock.h
+++ b/core/os/spin_lock.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index fc0ce3c9b4..f1fcfdf7e1 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -30,30 +30,77 @@
#include "thread.h"
-Thread *(*Thread::create_func)(ThreadCreateCallback, void *, const Settings &) = nullptr;
-Thread::ID (*Thread::get_thread_id_func)() = nullptr;
-void (*Thread::wait_to_finish_func)(Thread *) = nullptr;
+#include "core/object/script_language.h"
+
+#if !defined(NO_THREADS)
+
+#include "core/templates/safe_refcount.h"
+
Error (*Thread::set_name_func)(const String &) = nullptr;
+void (*Thread::set_priority_func)(Thread::Priority) = nullptr;
+void (*Thread::init_func)() = nullptr;
+void (*Thread::term_func)() = nullptr;
+
+uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) {
+ static std::hash<std::thread::id> hasher;
+ return hasher(p_t);
+}
+
+Thread::ID Thread::main_thread_id = _thread_id_hash(std::this_thread::get_id());
+thread_local Thread::ID Thread::caller_id = _thread_id_hash(std::this_thread::get_id());
-Thread::ID Thread::_main_thread_id = 0;
+void Thread::_set_platform_funcs(
+ Error (*p_set_name_func)(const String &),
+ void (*p_set_priority_func)(Thread::Priority),
+ void (*p_init_func)(),
+ void (*p_term_func)()) {
+ Thread::set_name_func = p_set_name_func;
+ Thread::set_priority_func = p_set_priority_func;
+ Thread::init_func = p_init_func;
+ Thread::term_func = p_term_func;
+}
-Thread::ID Thread::get_caller_id() {
- if (get_thread_id_func) {
- return get_thread_id_func();
+void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) {
+ Thread::caller_id = _thread_id_hash(p_self->thread.get_id());
+ if (set_priority_func) {
+ set_priority_func(p_settings.priority);
+ }
+ if (init_func) {
+ init_func();
+ }
+ ScriptServer::thread_enter(); //scripts may need to attach a stack
+ p_callback(p_userdata);
+ ScriptServer::thread_exit();
+ if (term_func) {
+ term_func();
}
- return 0;
}
-Thread *Thread::create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings) {
- if (create_func) {
- return create_func(p_callback, p_user, p_settings);
+void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_settings) {
+ if (id != _thread_id_hash(std::thread::id())) {
+#ifdef DEBUG_ENABLED
+ WARN_PRINT("A Thread object has been re-started without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
+#endif
+ thread.detach();
+ std::thread empty_thread;
+ thread.swap(empty_thread);
}
- return nullptr;
+ std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user);
+ thread.swap(new_thread);
+ id = _thread_id_hash(thread.get_id());
+}
+
+bool Thread::is_started() const {
+ return id != _thread_id_hash(std::thread::id());
}
-void Thread::wait_to_finish(Thread *p_thread) {
- if (wait_to_finish_func) {
- wait_to_finish_func(p_thread);
+void Thread::wait_to_finish() {
+ if (id != _thread_id_hash(std::thread::id())) {
+ ERR_FAIL_COND_MSG(id == get_caller_id(), "A Thread can't wait for itself to finish.");
+ thread.join();
+ std::thread empty_thread;
+ thread.swap(empty_thread);
+ id = _thread_id_hash(std::thread::id());
}
}
@@ -64,3 +111,14 @@ Error Thread::set_name(const String &p_name) {
return ERR_UNAVAILABLE;
}
+
+Thread::~Thread() {
+ if (id != _thread_id_hash(std::thread::id())) {
+#ifdef DEBUG_ENABLED
+ WARN_PRINT("A Thread object has been destroyed without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread.");
+#endif
+ thread.detach();
+ }
+}
+
+#endif
diff --git a/core/os/thread.h b/core/os/thread.h
index b87ec84313..599585051f 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -31,13 +31,21 @@
#ifndef THREAD_H
#define THREAD_H
-#include "core/string/ustring.h"
#include "core/typedefs.h"
-typedef void (*ThreadCreateCallback)(void *p_userdata);
+#if !defined(NO_THREADS)
+#include "core/templates/safe_refcount.h"
+#include <thread>
+#endif
+
+class String;
class Thread {
public:
+ typedef void (*Callback)(void *p_userdata);
+
+ typedef uint64_t ID;
+
enum Priority {
PRIORITY_LOW,
PRIORITY_NORMAL,
@@ -49,30 +57,61 @@ public:
Settings() { priority = PRIORITY_NORMAL; }
};
- typedef uint64_t ID;
+private:
+#if !defined(NO_THREADS)
+ friend class Main;
-protected:
- static Thread *(*create_func)(ThreadCreateCallback p_callback, void *, const Settings &);
- static ID (*get_thread_id_func)();
- static void (*wait_to_finish_func)(Thread *);
- static Error (*set_name_func)(const String &);
+ static ID main_thread_id;
- friend class Main;
+ static uint64_t _thread_id_hash(const std::thread::id &p_t);
+
+ ID id = _thread_id_hash(std::thread::id());
+ static thread_local ID caller_id;
+ std::thread thread;
- static ID _main_thread_id;
+ static void callback(Thread *p_self, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata);
- Thread() {}
+ static Error (*set_name_func)(const String &);
+ static void (*set_priority_func)(Thread::Priority);
+ static void (*init_func)();
+ static void (*term_func)();
+#endif
public:
- virtual ID get_id() const = 0;
+ static void _set_platform_funcs(
+ Error (*p_set_name_func)(const String &),
+ void (*p_set_priority_func)(Thread::Priority),
+ void (*p_init_func)() = nullptr,
+ void (*p_term_func)() = nullptr);
+
+#if !defined(NO_THREADS)
+ _FORCE_INLINE_ ID get_id() const { return id; }
+ // get the ID of the caller thread
+ _FORCE_INLINE_ static ID get_caller_id() { return caller_id; }
+ // get the ID of the main thread
+ _FORCE_INLINE_ static ID get_main_id() { return main_thread_id; }
static Error set_name(const String &p_name);
- _FORCE_INLINE_ static ID get_main_id() { return _main_thread_id; } ///< get the ID of the main thread
- static ID get_caller_id(); ///< get the ID of the caller function ID
- static void wait_to_finish(Thread *p_thread); ///< waits until thread is finished, and deallocates it.
- static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings()); ///< Static function to create a thread, will call p_callback
- virtual ~Thread() {}
+ void start(Thread::Callback p_callback, void *p_user, const Settings &p_settings = Settings());
+ bool is_started() const;
+ ///< waits until thread is finished, and deallocates it.
+ void wait_to_finish();
+
+ ~Thread();
+#else
+ _FORCE_INLINE_ ID get_id() const { return 0; }
+ // get the ID of the caller thread
+ _FORCE_INLINE_ static ID get_caller_id() { return 0; }
+ // get the ID of the main thread
+ _FORCE_INLINE_ static ID get_main_id() { return 0; }
+
+ static Error set_name(const String &p_name) { return ERR_UNAVAILABLE; }
+
+ void start(Thread::Callback p_callback, void *p_user, const Settings &p_settings = Settings()) {}
+ bool is_started() const { return false; }
+ void wait_to_finish() {}
+#endif
};
#endif // THREAD_H
diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp
deleted file mode 100644
index 2672cd7ad9..0000000000
--- a/core/os/thread_dummy.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/*************************************************************************/
-/* thread_dummy.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "thread_dummy.h"
-
-#include "core/os/memory.h"
-
-Thread *ThreadDummy::create(ThreadCreateCallback p_callback, void *p_user, const Thread::Settings &p_settings) {
- return memnew(ThreadDummy);
-}
-
-void ThreadDummy::make_default() {
- Thread::create_func = &ThreadDummy::create;
-}
-
-RWLock *RWLockDummy::create() {
- return memnew(RWLockDummy);
-}
-
-void RWLockDummy::make_default() {
- RWLock::create_func = &RWLockDummy::create;
-}
diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h
deleted file mode 100644
index 37d9ee0846..0000000000
--- a/core/os/thread_dummy.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* thread_dummy.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 THREAD_DUMMY_H
-#define THREAD_DUMMY_H
-
-#include "core/os/rw_lock.h"
-#include "core/os/semaphore.h"
-#include "core/os/thread.h"
-
-class ThreadDummy : public Thread {
- static Thread *create(ThreadCreateCallback p_callback, void *p_user, const Settings &p_settings = Settings());
-
-public:
- virtual ID get_id() const { return 0; };
-
- static void make_default();
-};
-
-class RWLockDummy : public RWLock {
- static RWLock *create();
-
-public:
- virtual void read_lock() {}
- virtual void read_unlock() {}
- virtual Error read_try_lock() { return OK; }
-
- virtual void write_lock() {}
- virtual void write_unlock() {}
- virtual Error write_try_lock() { return OK; }
-
- static void make_default();
-};
-
-#endif // THREAD_DUMMY_H
diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h
index 670ee8b125..81de079bf3 100644
--- a/core/os/thread_safe.h
+++ b/core/os/thread_safe.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/os/threaded_array_processor.h b/core/os/threaded_array_processor.h
index ed141a5339..fec6473589 100644
--- a/core/os/threaded_array_processor.h
+++ b/core/os/threaded_array_processor.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,7 +40,7 @@
template <class C, class U>
struct ThreadArrayProcessData {
uint32_t elements;
- uint32_t index;
+ SafeNumeric<uint32_t> index;
C *instance;
U userdata;
void (C::*method)(uint32_t, U);
@@ -56,7 +56,7 @@ template <class T>
void process_array_thread(void *ud) {
T &data = *(T *)ud;
while (true) {
- uint32_t index = atomic_increment(&data.index);
+ uint32_t index = data.index.increment();
if (index >= data.elements) {
break;
}
@@ -70,22 +70,21 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
data.method = p_method;
data.instance = p_instance;
data.userdata = p_userdata;
- data.index = 0;
+ data.index.set(0);
data.elements = p_elements;
- data.process(data.index); //process first, let threads increment for next
+ data.process(0); //process first, let threads increment for next
- Vector<Thread *> threads;
+ int thread_count = OS::get_singleton()->get_processor_count();
+ Thread *threads = memnew_arr(Thread, thread_count);
- threads.resize(OS::get_singleton()->get_processor_count());
-
- for (int i = 0; i < threads.size(); i++) {
- threads.write[i] = Thread::create(process_array_thread<ThreadArrayProcessData<C, U>>, &data);
+ for (int i = 0; i < thread_count; i++) {
+ threads[i].start(process_array_thread<ThreadArrayProcessData<C, U>>, &data);
}
- for (int i = 0; i < threads.size(); i++) {
- Thread::wait_to_finish(threads[i]);
- memdelete(threads[i]);
+ for (int i = 0; i < thread_count; i++) {
+ threads[i].wait_to_finish();
}
+ memdelete_arr(threads);
}
#else
@@ -96,7 +95,7 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
data.method = p_method;
data.instance = p_instance;
data.userdata = p_userdata;
- data.index = 0;
+ data.index.set(0);
data.elements = p_elements;
for (uint32_t i = 0; i < p_elements; i++) {
data.process(i);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 9883ce12a0..b58abc81d1 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -103,7 +103,6 @@ void register_core_types() {
static_assert(sizeof(Callable) <= 16);
ObjectDB::setup();
- ResourceCache::setup();
StringName::setup();
ResourceLoader::initialize();
diff --git a/core/register_core_types.h b/core/register_core_types.h
index bdd335f33c..baf7ddbe65 100644
--- a/core/register_core_types.h
+++ b/core/register_core_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/compressed_translation.cpp b/core/string/compressed_translation.cpp
index bdb296a79b..ad90924293 100644
--- a/core/string/compressed_translation.cpp
+++ b/core/string/compressed_translation.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/compressed_translation.h b/core/string/compressed_translation.h
index efb3535362..0abb770178 100644
--- a/core/string/compressed_translation.h
+++ b/core/string/compressed_translation.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp
index a63dde5b41..d3afa7b4dd 100644
--- a/core/string/node_path.cpp
+++ b/core/string/node_path.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/node_path.h b/core/string/node_path.h
index b4513ddb3c..26e15636d9 100644
--- a/core/string/node_path.h
+++ b/core/string/node_path.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp
index 54de229471..345371d733 100644
--- a/core/string/print_string.cpp
+++ b/core/string/print_string.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/print_string.h b/core/string/print_string.h
index 3e8f244cc5..1a9ff1efd6 100644
--- a/core/string/print_string.h
+++ b/core/string/print_string.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/string_buffer.h b/core/string/string_buffer.h
index 1317b538d4..33897c3674 100644
--- a/core/string/string_buffer.h
+++ b/core/string/string_buffer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,7 +40,7 @@ class StringBuffer {
int string_length = 0;
_FORCE_INLINE_ char32_t *current_buffer_ptr() {
- return static_cast<String &>(buffer).empty() ? short_buffer : buffer.ptrw();
+ return static_cast<String &>(buffer).is_empty() ? short_buffer : buffer.ptrw();
}
public:
@@ -122,7 +122,7 @@ StringBuffer<SHORT_BUFFER_SIZE> &StringBuffer<SHORT_BUFFER_SIZE>::reserve(int p_
return *this;
}
- bool need_copy = string_length > 0 && buffer.empty();
+ bool need_copy = string_length > 0 && buffer.is_empty();
buffer.resize(next_power_of_2(p_size));
if (need_copy) {
memcpy(buffer.ptrw(), short_buffer, string_length * sizeof(char32_t));
@@ -139,7 +139,7 @@ int StringBuffer<SHORT_BUFFER_SIZE>::length() const {
template <int SHORT_BUFFER_SIZE>
String StringBuffer<SHORT_BUFFER_SIZE>::as_string() {
current_buffer_ptr()[string_length] = '\0';
- if (buffer.empty()) {
+ if (buffer.is_empty()) {
return String(short_buffer);
} else {
buffer.resize(string_length + 1);
diff --git a/core/string/string_builder.cpp b/core/string/string_builder.cpp
index dec299ffa3..834c87c845 100644
--- a/core/string/string_builder.cpp
+++ b/core/string/string_builder.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/string_builder.h b/core/string/string_builder.h
index c732f1b9ea..30ce2a06f7 100644
--- a/core/string/string_builder.h
+++ b/core/string/string_builder.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index 34afdaee38..14b87072bb 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/string_name.h b/core/string/string_name.h
index 320f63bf68..44d0ea14fa 100644
--- a/core/string/string_name.h
+++ b/core/string/string_name.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -83,7 +83,7 @@ class StringName {
StringName(_Data *p_data) { _data = p_data; }
public:
- operator const void *() const { return (_data && (_data->cname || !_data->name.empty())) ? (void *)1 : nullptr; }
+ operator const void *() const { return (_data && (_data->cname || !_data->name.is_empty())) ? (void *)1 : nullptr; }
bool operator==(const String &p_name) const;
bool operator==(const char *p_name) const;
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 7b8c28e2e2..9cee218735 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -39,13 +39,14 @@
#include "main/main.h"
#endif
-// ISO 639-1 language codes, with the addition of glibc locales with their
-// regional identifiers. This list must match the language names (in English)
-// of locale_names.
+// ISO 639-1 language codes (and a couple of three-letter ISO 639-2 codes),
+// with the addition of glibc locales with their regional identifiers.
+// This list must match the language names (in English) of locale_names.
//
// References:
// - https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
// - https://lh.2xlibre.net/locales/
+// - https://iso639-3.sil.org/
static const char *locale_list[] = {
"aa", // Afar
@@ -100,6 +101,7 @@ static const char *locale_list[] = {
"bo", // Tibetan
"bo_CN", // Tibetan (China)
"bo_IN", // Tibetan (India)
+ "br", // Breton
"br_FR", // Breton (France)
"brx_IN", // Bodo (India)
"bs_BA", // Bosnian (Bosnia and Herzegovina)
@@ -201,6 +203,7 @@ static const char *locale_list[] = {
"gd_GB", // Scottish Gaelic (United Kingdom)
"gez_ER", // Geez (Eritrea)
"gez_ET", // Geez (Ethiopia)
+ "gl", // Galician
"gl_ES", // Galician (Spain)
"gu_IN", // Gujarati (India)
"gv_GB", // Manx (United Kingdom)
@@ -273,6 +276,7 @@ static const char *locale_list[] = {
"ml_IN", // Malayalam (India)
"mni_IN", // Manipuri (India)
"mn_MN", // Mongolian (Mongolia)
+ "mr", // Marathi
"mr_IN", // Marathi (India)
"ms", // Malay
"ms_MY", // Malay (Malaysia)
@@ -302,6 +306,7 @@ static const char *locale_list[] = {
"om", // Oromo
"om_ET", // Oromo (Ethiopia)
"om_KE", // Oromo (Kenya)
+ "or", // Oriya
"or_IN", // Oriya (India)
"os_RU", // Ossetian (Russia)
"pa_IN", // Panjabi (India)
@@ -386,6 +391,8 @@ static const char *locale_list[] = {
"tr_TR", // Turkish (Turkey)
"ts_ZA", // Tsonga (South Africa)
"tt_RU", // Tatar (Russia)
+ "tzm", // Central Atlas Tamazight
+ "tzm_MA", // Central Atlas Tamazight (Marrocos)
"ug_CN", // Uighur (China)
"uk", // Ukrainian
"uk_UA", // Ukrainian (Ukraine)
@@ -468,6 +475,7 @@ static const char *locale_names[] = {
"Tibetan",
"Tibetan (China)",
"Tibetan (India)",
+ "Breton",
"Breton (France)",
"Bodo (India)",
"Bosnian (Bosnia and Herzegovina)",
@@ -569,6 +577,7 @@ static const char *locale_names[] = {
"Scottish Gaelic (United Kingdom)",
"Geez (Eritrea)",
"Geez (Ethiopia)",
+ "Galician",
"Galician (Spain)",
"Gujarati (India)",
"Manx (United Kingdom)",
@@ -641,6 +650,7 @@ static const char *locale_names[] = {
"Malayalam (India)",
"Manipuri (India)",
"Mongolian (Mongolia)",
+ "Marathi",
"Marathi (India)",
"Malay",
"Malay (Malaysia)",
@@ -670,6 +680,7 @@ static const char *locale_names[] = {
"Oromo",
"Oromo (Ethiopia)",
"Oromo (Kenya)",
+ "Oriya",
"Oriya (India)",
"Ossetian (Russia)",
"Panjabi (India)",
@@ -754,6 +765,8 @@ static const char *locale_names[] = {
"Turkish (Turkey)",
"Tsonga (South Africa)",
"Tatar (Russia)",
+ "Central Atlas Tamazight",
+ "Central Atlas Tamazight (Marrocos)",
"Uighur (China)",
"Ukrainian",
"Ukrainian (Ukraine)",
@@ -851,7 +864,7 @@ void Translation::add_message(const StringName &p_src_text, const StringName &p_
void Translation::add_plural_message(const StringName &p_src_text, const Vector<String> &p_plural_xlated_texts, const StringName &p_context) {
WARN_PRINT("Translation class doesn't handle plural messages. Calling add_plural_message() on a Translation instance is probably a mistake. \nUse a derived Translation class that handles plurals, such as TranslationPO class");
- ERR_FAIL_COND_MSG(p_plural_xlated_texts.empty(), "Parameter vector p_plural_xlated_texts passed in is empty.");
+ ERR_FAIL_COND_MSG(p_plural_xlated_texts.is_empty(), "Parameter vector p_plural_xlated_texts passed in is empty.");
translation_map[p_src_text] = p_plural_xlated_texts[0];
}
@@ -1191,14 +1204,14 @@ bool TranslationServer::_load_translations(const String &p_from) {
}
void TranslationServer::setup() {
- String test = GLOBAL_DEF("locale/test", "");
+ String test = GLOBAL_DEF("internationalization/locale/test", "");
test = test.strip_edges();
if (test != "") {
set_locale(test);
} else {
set_locale(OS::get_singleton()->get_locale());
}
- fallback = GLOBAL_DEF("locale/fallback", "en");
+ fallback = GLOBAL_DEF("internationalization/locale/fallback", "en");
#ifdef TOOLS_ENABLED
{
String options = "";
@@ -1210,7 +1223,7 @@ void TranslationServer::setup() {
options += locale_list[idx];
idx++;
}
- ProjectSettings::get_singleton()->set_custom_property_info("locale/fallback", PropertyInfo(Variant::STRING, "locale/fallback", PROPERTY_HINT_ENUM, options));
+ ProjectSettings::get_singleton()->set_custom_property_info("internationalization/locale/fallback", PropertyInfo(Variant::STRING, "internationalization/locale/fallback", PROPERTY_HINT_ENUM, options));
}
#endif
}
@@ -1307,11 +1320,11 @@ void TranslationServer::_bind_methods() {
void TranslationServer::load_translations() {
String locale = get_locale();
- _load_translations("locale/translations"); //all
- _load_translations("locale/translations_" + locale.substr(0, 2));
+ _load_translations("internationalization/locale/translations"); //all
+ _load_translations("internationalization/locale/translations_" + locale.substr(0, 2));
if (locale.substr(0, 2) != locale) {
- _load_translations("locale/translations_" + locale);
+ _load_translations("internationalization/locale/translations_" + locale);
}
}
diff --git a/core/string/translation.h b/core/string/translation.h
index c7ffe4d065..72a828227e 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index 203f29026b..846afe761b 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -230,7 +230,7 @@ StringName TranslationPO::get_message(const StringName &p_src_text, const String
if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) {
return StringName();
}
- ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");
+ ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].is_empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");
return translation_map[p_context][p_src_text][0];
}
@@ -246,7 +246,7 @@ StringName TranslationPO::get_plural_message(const StringName &p_src_text, const
if (!translation_map.has(p_context) || !translation_map[p_context].has(p_src_text)) {
return StringName();
}
- ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");
+ ERR_FAIL_COND_V_MSG(translation_map[p_context][p_src_text].is_empty(), StringName(), "Source text \"" + String(p_src_text) + "\" is registered but doesn't have a translation. Please report this bug.");
if (translation_map[p_context][p_src_text].size() == 1) {
WARN_PRINT("Source string \"" + String(p_src_text) + "\" doesn't have plural translations. Use singular translation API for such as tr(), TTR() to translate \"" + String(p_src_text) + "\"");
diff --git a/core/string/translation_po.h b/core/string/translation_po.h
index c8a47bec5a..0e1d03d6ca 100644
--- a/core/string/translation_po.h
+++ b/core/string/translation_po.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/ucaps.h b/core/string/ucaps.h
index 79b346acba..b785ac7879 100644
--- a/core/string/ucaps.h
+++ b/core/string/ucaps.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index d630e987ea..a57c7b2504 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -427,12 +427,12 @@ String operator+(char32_t p_chr, const String &p_str) {
}
String &String::operator+=(const String &p_str) {
- if (empty()) {
+ if (is_empty()) {
*this = p_str;
return *this;
}
- if (p_str.empty()) {
+ if (p_str.is_empty()) {
return *this;
}
@@ -519,7 +519,7 @@ bool String::operator==(const char *p_str) const {
if (length() != len) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
@@ -558,7 +558,7 @@ bool String::operator==(const char32_t *p_str) const {
if (length() != len) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
@@ -580,7 +580,7 @@ bool String::operator==(const String &p_str) const {
if (length() != p_str.length()) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
@@ -605,7 +605,7 @@ bool String::operator==(const StrRange &p_str_range) const {
if (length() != len) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
@@ -678,20 +678,20 @@ bool String::operator>=(const String &p_str) const {
}
bool String::operator<(const char *p_str) const {
- if (empty() && p_str[0] == 0) {
+ if (is_empty() && p_str[0] == 0) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
return is_str_less(get_data(), p_str);
}
bool String::operator<(const wchar_t *p_str) const {
- if (empty() && p_str[0] == 0) {
+ if (is_empty() && p_str[0] == 0) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
@@ -705,10 +705,10 @@ bool String::operator<(const wchar_t *p_str) const {
}
bool String::operator<(const char32_t *p_str) const {
- if (empty() && p_str[0] == 0) {
+ if (is_empty() && p_str[0] == 0) {
return false;
}
- if (empty()) {
+ if (is_empty()) {
return true;
}
@@ -720,13 +720,13 @@ bool String::operator<(const String &p_str) const {
}
signed char String::nocasecmp_to(const String &p_str) const {
- if (empty() && p_str.empty()) {
+ if (is_empty() && p_str.is_empty()) {
return 0;
}
- if (empty()) {
+ if (is_empty()) {
return -1;
}
- if (p_str.empty()) {
+ if (p_str.is_empty()) {
return 1;
}
@@ -752,13 +752,13 @@ signed char String::nocasecmp_to(const String &p_str) const {
}
signed char String::casecmp_to(const String &p_str) const {
- if (empty() && p_str.empty()) {
+ if (is_empty() && p_str.is_empty()) {
return 0;
}
- if (empty()) {
+ if (is_empty()) {
return -1;
}
- if (p_str.empty()) {
+ if (p_str.is_empty()) {
return 1;
}
@@ -949,10 +949,10 @@ String String::get_with_code_lines() const {
}
int String::get_slice_count(String p_splitter) const {
- if (empty()) {
+ if (is_empty()) {
return 0;
}
- if (p_splitter.empty()) {
+ if (p_splitter.is_empty()) {
return 0;
}
@@ -968,7 +968,7 @@ int String::get_slice_count(String p_splitter) const {
}
String String::get_slice(String p_splitter, int p_slice) const {
- if (empty() || p_splitter.empty()) {
+ if (is_empty() || p_splitter.is_empty()) {
return "";
}
@@ -1008,7 +1008,7 @@ String String::get_slice(String p_splitter, int p_slice) const {
}
String String::get_slicec(char32_t p_splitter, int p_slice) const {
- if (empty()) {
+ if (is_empty()) {
return String();
}
@@ -1409,8 +1409,9 @@ String String::num(double p_num, int p_decimals) {
if (digit == MAX_DIGITS) //no point in going to infinite
break;
- if ((dec - (double)((int)dec)) < 1e-6)
+ if (dec - (double)((int)dec) < 1e-6) {
break;
+ }
}
if (digit == p_decimals)
@@ -2096,8 +2097,9 @@ String::String(const StrRange &p_range) {
copy_from(p_range.c_str, p_range.len);
}
-int64_t String::hex_to_int(bool p_with_prefix) const {
- if (p_with_prefix && length() < 3) {
+int64_t String::hex_to_int() const {
+ int len = length();
+ if (len == 0) {
return 0;
}
@@ -2109,10 +2111,7 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
s++;
}
- if (p_with_prefix) {
- if (s[0] != '0' || s[1] != 'x') {
- return 0;
- }
+ if (len > 2 && s[0] == '0' && s[1] == 'x') {
s += 2;
}
@@ -2139,8 +2138,9 @@ int64_t String::hex_to_int(bool p_with_prefix) const {
return hex * sign;
}
-int64_t String::bin_to_int(bool p_with_prefix) const {
- if (p_with_prefix && length() < 3) {
+int64_t String::bin_to_int() const {
+ int len = length();
+ if (len == 0) {
return 0;
}
@@ -2152,10 +2152,7 @@ int64_t String::bin_to_int(bool p_with_prefix) const {
s++;
}
- if (p_with_prefix) {
- if (s[0] != '0' || s[1] != 'b') {
- return 0;
- }
+ if (len > 2 && s[0] == '0' && s[1] == 'b') {
s += 2;
}
@@ -2585,7 +2582,7 @@ int64_t String::to_int(const char32_t *p_str, int p_len, bool p_clamp) {
}
double String::to_float() const {
- if (empty()) {
+ if (is_empty()) {
return 0;
}
return built_in_strtod<char32_t>(get_data());
@@ -2767,7 +2764,7 @@ String String::substr(int p_from, int p_chars) const {
p_chars = length() - p_from;
}
- if (empty() || p_from < 0 || p_from >= length() || p_chars <= 0) {
+ if (is_empty() || p_from < 0 || p_from >= length() || p_chars <= 0) {
return "";
}
@@ -3074,35 +3071,47 @@ int String::rfindn(const String &p_str, int p_from) const {
}
bool String::ends_with(const String &p_string) const {
- int pos = rfind(p_string);
- if (pos == -1) {
+ int l = p_string.length();
+ if (l > length()) {
return false;
}
- return pos + p_string.length() == length();
+
+ if (l == 0) {
+ return true;
+ }
+
+ const char32_t *p = &p_string[0];
+ const char32_t *s = &operator[](length() - l);
+
+ for (int i = 0; i < l; i++) {
+ if (p[i] != s[i]) {
+ return false;
+ }
+ }
+
+ return true;
}
bool String::begins_with(const String &p_string) const {
- if (p_string.length() > length()) {
+ int l = p_string.length();
+ if (l > length()) {
return false;
}
- int l = p_string.length();
if (l == 0) {
return true;
}
- const char32_t *src = &p_string[0];
- const char32_t *str = &operator[](0);
+ const char32_t *p = &p_string[0];
+ const char32_t *s = &operator[](0);
- int i = 0;
- for (; i < l; i++) {
- if (src[i] != str[i]) {
+ for (int i = 0; i < l; i++) {
+ if (p[i] != s[i]) {
return false;
}
}
- // only if i == l the p_string matches the beginning
- return i == l;
+ return true;
}
bool String::begins_with(const char *p_string) const {
@@ -3142,7 +3151,7 @@ bool String::is_quoted() const {
}
int String::_count(const String &p_string, int p_from, int p_to, bool p_case_insensitive) const {
- if (p_string.empty()) {
+ if (p_string.is_empty()) {
return 0;
}
int len = length();
@@ -3250,8 +3259,8 @@ float String::similarity(const String &p_string) const {
int src_size = src_bigrams.size();
int tgt_size = tgt_bigrams.size();
- double sum = src_size + tgt_size;
- double inter = 0;
+ int sum = src_size + tgt_size;
+ int inter = 0;
for (int i = 0; i < src_size; i++) {
for (int j = 0; j < tgt_size; j++) {
if (src_bigrams[i] == tgt_bigrams[j]) {
@@ -3478,7 +3487,7 @@ String String::right(int p_pos) const {
return substr(p_pos, (length() - p_pos));
}
-char32_t String::ord_at(int p_idx) const {
+char32_t String::unicode_at(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, length(), 0);
return operator[](p_idx);
}
@@ -3750,7 +3759,7 @@ bool String::is_valid_string() const {
return valid;
}
-String String::http_escape() const {
+String String::uri_encode() const {
const CharString temp = utf8();
String res;
for (int i = 0; i < temp.length(); ++i) {
@@ -3774,23 +3783,25 @@ String String::http_escape() const {
return res;
}
-String String::http_unescape() const {
+String String::uri_decode() const {
String res;
for (int i = 0; i < length(); ++i) {
- if (ord_at(i) == '%' && i + 2 < length()) {
- char32_t ord1 = ord_at(i + 1);
+ if (unicode_at(i) == '%' && i + 2 < length()) {
+ char32_t ord1 = unicode_at(i + 1);
if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
- char32_t ord2 = ord_at(i + 2);
+ char32_t ord2 = unicode_at(i + 2);
if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
char bytes[3] = { (char)ord1, (char)ord2, 0 };
res += (char)strtol(bytes, nullptr, 16);
i += 2;
}
} else {
- res += ord_at(i);
+ res += unicode_at(i);
}
+ } else if (unicode_at(i) == '+') {
+ res += ' ';
} else {
- res += ord_at(i);
+ res += unicode_at(i);
}
}
return String::utf8(res.ascii());
@@ -3877,25 +3888,55 @@ static _FORCE_INLINE_ int _xml_unescape(const char32_t *p_src, int p_src_len, ch
if (p_src_len >= 4 && p_src[1] == '#') {
char32_t c = 0;
-
- for (int i = 2; i < p_src_len; i++) {
- eat = i + 1;
- char32_t ct = p_src[i];
- if (ct == ';') {
- break;
- } else if (ct >= '0' && ct <= '9') {
- ct = ct - '0';
- } else if (ct >= 'a' && ct <= 'f') {
- ct = (ct - 'a') + 10;
- } else if (ct >= 'A' && ct <= 'F') {
- ct = (ct - 'A') + 10;
- } else {
- continue;
+ bool overflow = false;
+ if (p_src[2] == 'x') {
+ // Hex entity &#x<num>;
+ for (int i = 3; i < p_src_len; i++) {
+ eat = i + 1;
+ char32_t ct = p_src[i];
+ if (ct == ';') {
+ break;
+ } else if (ct >= '0' && ct <= '9') {
+ ct = ct - '0';
+ } else if (ct >= 'a' && ct <= 'f') {
+ ct = (ct - 'a') + 10;
+ } else if (ct >= 'A' && ct <= 'F') {
+ ct = (ct - 'A') + 10;
+ } else {
+ break;
+ }
+ if (c > (UINT32_MAX >> 4)) {
+ overflow = true;
+ break;
+ }
+ c <<= 4;
+ c |= ct;
+ }
+ } else {
+ // Decimal entity &#<num>;
+ for (int i = 2; i < p_src_len; i++) {
+ eat = i + 1;
+ char32_t ct = p_src[i];
+ if (ct == ';' || ct < '0' || ct > '9') {
+ break;
+ }
+ }
+ if (p_src[eat - 1] == ';') {
+ int64_t val = String::to_int(p_src + 2, eat - 3);
+ if (val > 0 && val <= UINT32_MAX) {
+ c = (char32_t)val;
+ } else {
+ overflow = true;
+ }
}
- c <<= 4;
- c |= ct;
}
+ // Value must be non-zero, in the range of char32_t,
+ // actually end with ';'. If invalid, leave the entity as-is
+ if (c == '\0' || overflow || p_src[eat - 1] != ';') {
+ eat = 1;
+ c = *p_src;
+ }
if (p_dst) {
*p_dst = c;
}
@@ -4241,11 +4282,11 @@ bool String::is_valid_ip_address() const {
Vector<String> ip = split(":");
for (int i = 0; i < ip.size(); i++) {
String n = ip[i];
- if (n.empty()) {
+ if (n.is_empty()) {
continue;
}
if (n.is_valid_hex_number(false)) {
- int64_t nint = n.hex_to_int(false);
+ int64_t nint = n.hex_to_int();
if (nint < 0 || nint > 0xffff) {
return false;
}
@@ -4285,7 +4326,10 @@ bool String::is_rel_path() const {
}
String String::get_base_dir() const {
- int basepos = find("://");
+ int basepos = find(":/");
+ if (basepos == -1) {
+ basepos = find(":\\");
+ }
String rs;
String base;
if (basepos != -1) {
@@ -4328,7 +4372,7 @@ String String::get_extension() const {
}
String String::plus_file(const String &p_file) const {
- if (empty()) {
+ if (is_empty()) {
return p_file;
}
if (operator[](length() - 1) == '/' || (p_file.size() > 0 && p_file.operator[](0) == '/')) {
@@ -4337,63 +4381,6 @@ String String::plus_file(const String &p_file) const {
return *this + "/" + p_file;
}
-String String::percent_encode() const {
- CharString cs = utf8();
- String encoded;
- for (int i = 0; i < cs.length(); i++) {
- uint8_t c = cs[i];
- if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '~' || c == '.') {
- char p[2] = { (char)c, 0 };
- encoded += p;
- } else {
- char p[4] = { '%', 0, 0, 0 };
- static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- p[1] = hex[c >> 4];
- p[2] = hex[c & 0xF];
- encoded += p;
- }
- }
-
- return encoded;
-}
-
-String String::percent_decode() const {
- CharString pe;
-
- CharString cs = utf8();
- for (int i = 0; i < cs.length(); i++) {
- uint8_t c = cs[i];
- if (c == '%' && i < length() - 2) {
- uint8_t a = LOWERCASE(cs[i + 1]);
- uint8_t b = LOWERCASE(cs[i + 2]);
-
- if (a >= '0' && a <= '9') {
- c = (a - '0') << 4;
- } else if (a >= 'a' && a <= 'f') {
- c = (a - 'a' + 10) << 4;
- } else {
- continue;
- }
-
- uint8_t d = 0;
-
- if (b >= '0' && b <= '9') {
- d = (b - '0');
- } else if (b >= 'a' && b <= 'f') {
- d = (b - 'a' + 10);
- } else {
- continue;
- }
- c += d;
- i += 2;
- }
- pe += c;
- }
-
- return String::utf8(pe.ptr());
-}
-
String String::property_name_encode() const {
// Escape and quote strings with extended ASCII or further Unicode characters
// as well as '"', '=' or ' ' (32)
@@ -4757,7 +4744,7 @@ String String::unquote() const {
Vector<uint8_t> String::to_ascii_buffer() const {
const String *s = this;
- if (s->empty()) {
+ if (s->is_empty()) {
return Vector<uint8_t>();
}
CharString charstr = s->ascii();
@@ -4773,7 +4760,7 @@ Vector<uint8_t> String::to_ascii_buffer() const {
Vector<uint8_t> String::to_utf8_buffer() const {
const String *s = this;
- if (s->empty()) {
+ if (s->is_empty()) {
return Vector<uint8_t>();
}
CharString charstr = s->utf8();
@@ -4789,7 +4776,7 @@ Vector<uint8_t> String::to_utf8_buffer() const {
Vector<uint8_t> String::to_utf16_buffer() const {
const String *s = this;
- if (s->empty()) {
+ if (s->is_empty()) {
return Vector<uint8_t>();
}
Char16String charstr = s->utf16();
@@ -4805,7 +4792,7 @@ Vector<uint8_t> String::to_utf16_buffer() const {
Vector<uint8_t> String::to_utf32_buffer() const {
const String *s = this;
- if (s->empty()) {
+ if (s->is_empty()) {
return Vector<uint8_t>();
}
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 7ff78b2d86..821941036f 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -318,8 +318,8 @@ public:
bool is_numeric() const;
double to_float() const;
- int64_t hex_to_int(bool p_with_prefix = true) const;
- int64_t bin_to_int(bool p_with_prefix = true) const;
+ int64_t hex_to_int() const;
+ int64_t bin_to_int() const;
int64_t to_int() const;
static int64_t to_int(const char *p_str, int p_len = -1);
@@ -366,7 +366,7 @@ public:
String get_extension() const;
String get_basename() const;
String plus_file(const String &p_file) const;
- char32_t ord_at(int p_idx) const;
+ char32_t unicode_at(int p_idx) const;
void erase(int p_pos, int p_chars);
@@ -394,7 +394,7 @@ public:
Vector<uint8_t> sha1_buffer() const;
Vector<uint8_t> sha256_buffer() const;
- _FORCE_INLINE_ bool empty() const { return length() == 0; }
+ _FORCE_INLINE_ bool is_empty() const { return length() == 0; }
// path functions
bool is_abs_path() const;
@@ -409,17 +409,14 @@ public:
String xml_escape(bool p_escape_quotes = false) const;
String xml_unescape() const;
- String http_escape() const;
- String http_unescape() const;
+ String uri_encode() const;
+ String uri_decode() const;
String c_escape() const;
String c_escape_multiline() const;
String c_unescape() const;
String json_escape() const;
String word_wrap(int p_chars_per_line) const;
- String percent_encode() const;
- String percent_decode() const;
-
String property_name_encode() const;
bool is_valid_identifier() const;
diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp
index a94853a21c..238bf3975c 100644
--- a/core/templates/command_queue_mt.cpp
+++ b/core/templates/command_queue_mt.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index ac38d330de..0012cea72d 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -498,6 +498,11 @@ public:
flush_one();
}
+ _FORCE_INLINE_ void flush_if_pending() {
+ if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) {
+ flush_all();
+ }
+ }
void flush_all() {
//ERR_FAIL_COND(sync);
lock();
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index d5eb08286d..c985593473 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -45,6 +45,10 @@ class CharString;
template <class T, class V>
class VMap;
+#if !defined(NO_THREADS)
+SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint32_t)
+#endif
+
template <class T>
class CowData {
template <class TV>
@@ -60,12 +64,12 @@ private:
// internal helpers
- _FORCE_INLINE_ uint32_t *_get_refcount() const {
+ _FORCE_INLINE_ SafeNumeric<uint32_t> *_get_refcount() const {
if (!_ptr) {
return nullptr;
}
- return reinterpret_cast<uint32_t *>(_ptr) - 2;
+ return reinterpret_cast<SafeNumeric<uint32_t> *>(_ptr) - 2;
}
_FORCE_INLINE_ uint32_t *_get_size() const {
@@ -111,7 +115,7 @@ private:
void _unref(void *p_data);
void _ref(const CowData *p_from);
void _ref(const CowData &p_from);
- void _copy_on_write();
+ uint32_t _copy_on_write();
public:
void operator=(const CowData<T> &p_from) { _ref(p_from); }
@@ -135,10 +139,10 @@ public:
}
_FORCE_INLINE_ void clear() { resize(0); }
- _FORCE_INLINE_ bool empty() const { return _ptr == nullptr; }
+ _FORCE_INLINE_ bool is_empty() const { return _ptr == nullptr; }
_FORCE_INLINE_ void set(int p_index, const T &p_elem) {
- CRASH_BAD_INDEX(p_index, size());
+ ERR_FAIL_INDEX(p_index, size());
_copy_on_write();
_get_data()[p_index] = p_elem;
}
@@ -192,9 +196,9 @@ void CowData<T>::_unref(void *p_data) {
return;
}
- uint32_t *refc = _get_refcount();
+ SafeNumeric<uint32_t> *refc = _get_refcount();
- if (atomic_decrement(refc) > 0) {
+ if (refc->decrement() > 0) {
return; // still in use
}
// clean up
@@ -214,20 +218,21 @@ void CowData<T>::_unref(void *p_data) {
}
template <class T>
-void CowData<T>::_copy_on_write() {
+uint32_t CowData<T>::_copy_on_write() {
if (!_ptr) {
- return;
+ return 0;
}
- uint32_t *refc = _get_refcount();
+ SafeNumeric<uint32_t> *refc = _get_refcount();
- if (unlikely(*refc > 1)) {
+ uint32_t rc = refc->get();
+ if (unlikely(rc > 1)) {
/* in use by more than me */
uint32_t current_size = *_get_size();
uint32_t *mem_new = (uint32_t *)Memory::alloc_static(_get_alloc_size(current_size), true);
- *(mem_new - 2) = 1; //refcount
+ new (mem_new - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(1); //refcount
*(mem_new - 1) = current_size; //size
T *_data = (T *)(mem_new);
@@ -244,7 +249,10 @@ void CowData<T>::_copy_on_write() {
_unref(_ptr);
_ptr = _data;
+
+ rc = 1;
}
+ return rc;
}
template <class T>
@@ -265,7 +273,7 @@ Error CowData<T>::resize(int p_size) {
}
// possibly changing size, copy on write
- _copy_on_write();
+ uint32_t rc = _copy_on_write();
size_t current_alloc_size = _get_alloc_size(current_size);
size_t alloc_size;
@@ -278,13 +286,15 @@ Error CowData<T>::resize(int p_size) {
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; //size, currently none
- *(ptr - 2) = 1; //refcount
+ new (ptr - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(1); //refcount
_ptr = (T *)ptr;
} else {
- void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+ uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ new (_ptrnew - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(rc); //refcount
+
_ptr = (T *)(_ptrnew);
}
}
@@ -311,8 +321,9 @@ Error CowData<T>::resize(int p_size) {
}
if (alloc_size != current_alloc_size) {
- void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+ uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ new (_ptrnew - 2, sizeof(uint32_t), "") SafeNumeric<uint32_t>(rc); //refcount
_ptr = (T *)(_ptrnew);
}
@@ -359,7 +370,7 @@ void CowData<T>::_ref(const CowData &p_from) {
return; //nothing to do
}
- if (atomic_conditional_increment(p_from._get_refcount()) > 0) { // could reference
+ if (p_from._get_refcount()->conditional_increment() > 0) { // could reference
_ptr = p_from._ptr;
}
}
diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h
index e1ba381595..dc378aed69 100644
--- a/core/templates/hash_map.h
+++ b/core/templates/hash_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -497,7 +497,7 @@ public:
return elements;
}
- inline bool empty() const {
+ inline bool is_empty() const {
return elements == 0;
}
diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h
index 1ed9ab1987..4572b269cf 100644
--- a/core/templates/hashfuncs.h
+++ b/core/templates/hashfuncs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/list.h b/core/templates/list.h
index 8e14aaa90d..eaf1dbb4a0 100644
--- a/core/templates/list.h
+++ b/core/templates/list.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -373,7 +373,7 @@ public:
/**
* return whether the list is empty
*/
- _FORCE_INLINE_ bool empty() const {
+ _FORCE_INLINE_ bool is_empty() const {
return (!_data || !_data->size_cache);
}
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 4ef040dc77..ffd17b7ee9 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -82,6 +82,19 @@ public:
}
}
+ /// Removes the item copying the last value into the position of the one to
+ /// remove. It's generally faster than `remove`.
+ void remove_unordered(U p_index) {
+ ERR_FAIL_INDEX(p_index, count);
+ count--;
+ if (count > p_index) {
+ data[p_index] = data[count];
+ }
+ if (!__has_trivial_destructor(T) && !force_trivial) {
+ data[count].~T();
+ }
+ }
+
void erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
@@ -104,7 +117,8 @@ public:
capacity = 0;
}
}
- _FORCE_INLINE_ bool empty() const { return count == 0; }
+ _FORCE_INLINE_ bool is_empty() const { return count == 0; }
+ _FORCE_INLINE_ U get_capacity() const { return capacity; }
_FORCE_INLINE_ void reserve(U p_size) {
p_size = nearest_power_of_2_templated(p_size);
if (p_size > capacity) {
diff --git a/core/templates/lru.h b/core/templates/lru.h
index d02c4337d1..e55e40da48 100644
--- a/core/templates/lru.h
+++ b/core/templates/lru.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/map.h b/core/templates/map.h
index c454d69256..51a237472d 100644
--- a/core/templates/map.h
+++ b/core/templates/map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -625,7 +625,7 @@ public:
return e;
}
- inline bool empty() const { return _data.size_cache == 0; }
+ inline bool is_empty() const { return _data.size_cache == 0; }
inline int size() const { return _data.size_cache; }
int calculate_depth() const {
diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h
index d9d632b4ce..1d4176eb10 100644
--- a/core/templates/oa_hash_map.h
+++ b/core/templates/oa_hash_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -190,7 +190,7 @@ public:
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity; }
_FORCE_INLINE_ uint32_t get_num_elements() const { return num_elements; }
- bool empty() const {
+ bool is_empty() const {
return num_elements == 0;
}
diff --git a/core/templates/ordered_hash_map.h b/core/templates/ordered_hash_map.h
index 9398868b01..7a17eeb644 100644
--- a/core/templates/ordered_hash_map.h
+++ b/core/templates/ordered_hash_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -265,7 +265,7 @@ public:
return ConstElement(list.back());
}
- inline bool empty() const { return list.empty(); }
+ inline bool is_empty() const { return list.is_empty(); }
inline int size() const { return list.size(); }
const void *id() const {
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
new file mode 100644
index 0000000000..7002034710
--- /dev/null
+++ b/core/templates/paged_allocator.h
@@ -0,0 +1,129 @@
+/*************************************************************************/
+/* paged_allocator.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 PAGED_ALLOCATOR_H
+#define PAGED_ALLOCATOR_H
+
+#include "core/os/memory.h"
+#include "core/os/spin_lock.h"
+#include "core/typedefs.h"
+
+template <class T, bool thread_safe = false>
+class PagedAllocator {
+ T **page_pool = nullptr;
+ T ***available_pool = nullptr;
+ uint32_t pages_allocated = 0;
+ uint32_t allocs_available = 0;
+
+ uint32_t page_shift = 0;
+ uint32_t page_mask = 0;
+ uint32_t page_size = 0;
+ SpinLock spin_lock;
+
+public:
+ T *alloc() {
+ if (thread_safe) {
+ spin_lock.lock();
+ }
+ if (unlikely(allocs_available == 0)) {
+ uint32_t pages_used = pages_allocated;
+
+ pages_allocated++;
+ page_pool = (T **)memrealloc(page_pool, sizeof(T *) * pages_allocated);
+ available_pool = (T ***)memrealloc(available_pool, sizeof(T **) * pages_allocated);
+
+ page_pool[pages_used] = (T *)memalloc(sizeof(T) * page_size);
+ available_pool[pages_used] = (T **)memalloc(sizeof(T *) * page_size);
+
+ for (uint32_t i = 0; i < page_size; i++) {
+ available_pool[0][i] = &page_pool[pages_used][i];
+ }
+ allocs_available += page_size;
+ }
+
+ allocs_available--;
+ T *alloc = available_pool[allocs_available >> page_shift][allocs_available & page_mask];
+ if (thread_safe) {
+ spin_lock.unlock();
+ }
+ memnew_placement(alloc, T);
+ return alloc;
+ }
+
+ void free(T *p_mem) {
+ if (thread_safe) {
+ spin_lock.lock();
+ }
+ p_mem->~T();
+ available_pool[allocs_available >> page_shift][allocs_available & page_mask] = p_mem;
+ if (thread_safe) {
+ spin_lock.unlock();
+ }
+ allocs_available++;
+ }
+
+ void reset() {
+ ERR_FAIL_COND(allocs_available < pages_allocated * page_size);
+ if (pages_allocated) {
+ for (uint32_t i = 0; i < pages_allocated; i++) {
+ memfree(page_pool[i]);
+ memfree(available_pool[i]);
+ }
+ memfree(page_pool);
+ memfree(available_pool);
+ page_pool = nullptr;
+ available_pool = nullptr;
+ pages_allocated = 0;
+ allocs_available = 0;
+ }
+ }
+ bool is_configured() const {
+ return page_size > 0;
+ }
+
+ void configure(uint32_t p_page_size) {
+ ERR_FAIL_COND(page_pool != nullptr); //sanity check
+ ERR_FAIL_COND(p_page_size == 0);
+ page_size = nearest_power_of_2_templated(p_page_size);
+ page_mask = page_size - 1;
+ page_shift = get_shift_from_power_of_2(page_size);
+ }
+
+ PagedAllocator(uint32_t p_page_size = 4096) { // power of 2 recommended because of alignment with OS page sizes. Even if element is bigger, its still a multiple and get rounded amount of pages
+ configure(p_page_size);
+ }
+
+ ~PagedAllocator() {
+ ERR_FAIL_COND_MSG(allocs_available < pages_allocated * page_size, "Pages in use exist at exit in PagedAllocator");
+ reset();
+ }
+};
+
+#endif // PAGED_ALLOCATOR_H
diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h
new file mode 100644
index 0000000000..599d3dde4f
--- /dev/null
+++ b/core/templates/paged_array.h
@@ -0,0 +1,367 @@
+/*************************************************************************/
+/* paged_array.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 PAGED_ARRAY_H
+#define PAGED_ARRAY_H
+
+#include "core/os/memory.h"
+#include "core/os/spin_lock.h"
+#include "core/typedefs.h"
+
+// PagedArray is used mainly for filling a very large array from multiple threads efficiently and without causing major fragmentation
+
+// PageArrayPool manages central page allocation in a thread safe matter
+
+template <class T>
+class PagedArrayPool {
+ T **page_pool = nullptr;
+ uint32_t pages_allocated = 0;
+
+ uint32_t *available_page_pool = nullptr;
+ uint32_t pages_available = 0;
+
+ uint32_t page_size = 0;
+ SpinLock spin_lock;
+
+public:
+ uint32_t alloc_page() {
+ spin_lock.lock();
+ if (unlikely(pages_available == 0)) {
+ uint32_t pages_used = pages_allocated;
+
+ pages_allocated++;
+ page_pool = (T **)memrealloc(page_pool, sizeof(T *) * pages_allocated);
+ available_page_pool = (uint32_t *)memrealloc(available_page_pool, sizeof(uint32_t) * pages_allocated);
+
+ page_pool[pages_used] = (T *)memalloc(sizeof(T) * page_size);
+ available_page_pool[0] = pages_used;
+
+ pages_available++;
+ }
+
+ pages_available--;
+ uint32_t page = available_page_pool[pages_available];
+ spin_lock.unlock();
+
+ return page;
+ }
+ T *get_page(uint32_t p_page_id) {
+ return page_pool[p_page_id];
+ }
+
+ void free_page(uint32_t p_page_id) {
+ spin_lock.lock();
+ available_page_pool[pages_available] = p_page_id;
+ pages_available++;
+ spin_lock.unlock();
+ }
+
+ uint32_t get_page_size_shift() const {
+ return get_shift_from_power_of_2(page_size);
+ }
+
+ uint32_t get_page_size_mask() const {
+ return page_size - 1;
+ }
+
+ void reset() {
+ ERR_FAIL_COND(pages_available < pages_allocated);
+ if (pages_allocated) {
+ for (uint32_t i = 0; i < pages_allocated; i++) {
+ memfree(page_pool[i]);
+ }
+ memfree(page_pool);
+ memfree(available_page_pool);
+ page_pool = nullptr;
+ available_page_pool = nullptr;
+ pages_allocated = 0;
+ pages_available = 0;
+ }
+ }
+ bool is_configured() const {
+ return page_size > 0;
+ }
+
+ void configure(uint32_t p_page_size) {
+ ERR_FAIL_COND(page_pool != nullptr); //sanity check
+ ERR_FAIL_COND(p_page_size == 0);
+ page_size = nearest_power_of_2_templated(p_page_size);
+ }
+
+ PagedArrayPool(uint32_t p_page_size = 4096) { // power of 2 recommended because of alignment with OS page sizes. Even if element is bigger, its still a multiple and get rounded amount of pages
+ configure(p_page_size);
+ }
+
+ ~PagedArrayPool() {
+ ERR_FAIL_COND_MSG(pages_available < pages_allocated, "Pages in use exist at exit in PagedArrayPool");
+ reset();
+ }
+};
+
+// PageArray is a local array that is optimized to grow in place, then be cleared often.
+// It does so by allocating pages from a PagedArrayPool.
+// It is safe to use multiple PagedArrays from different threads, sharing a single PagedArrayPool
+
+template <class T>
+class PagedArray {
+ PagedArrayPool<T> *page_pool = nullptr;
+
+ T **page_data = nullptr;
+ uint32_t *page_ids = nullptr;
+ uint32_t max_pages_used = 0;
+ uint32_t page_size_shift = 0;
+ uint32_t page_size_mask = 0;
+ uint64_t count = 0;
+
+ _FORCE_INLINE_ uint32_t _get_pages_in_use() const {
+ if (count == 0) {
+ return 0;
+ } else {
+ return ((count - 1) >> page_size_shift) + 1;
+ }
+ }
+
+ void _grow_page_array() {
+ //no more room in the page array to put the new page, make room
+ if (max_pages_used == 0) {
+ max_pages_used = 1;
+ } else {
+ max_pages_used *= 2; // increase in powers of 2 to keep allocations to minimum
+ }
+ page_data = (T **)memrealloc(page_data, sizeof(T *) * max_pages_used);
+ page_ids = (uint32_t *)memrealloc(page_ids, sizeof(uint32_t) * max_pages_used);
+ }
+
+public:
+ _FORCE_INLINE_ const T &operator[](uint64_t p_index) const {
+ CRASH_BAD_UNSIGNED_INDEX(p_index, count);
+ uint32_t page = p_index >> page_size_shift;
+ uint32_t offset = p_index & page_size_mask;
+
+ return page_data[page][offset];
+ }
+ _FORCE_INLINE_ T &operator[](uint64_t p_index) {
+ CRASH_BAD_UNSIGNED_INDEX(p_index, count);
+ uint32_t page = p_index >> page_size_shift;
+ uint32_t offset = p_index & page_size_mask;
+
+ return page_data[page][offset];
+ }
+
+ _FORCE_INLINE_ void push_back(const T &p_value) {
+ uint32_t remainder = count & page_size_mask;
+ if (unlikely(remainder == 0)) {
+ // at 0, so time to request a new page
+ uint32_t page_count = _get_pages_in_use();
+ uint32_t new_page_count = page_count + 1;
+
+ if (unlikely(new_page_count > max_pages_used)) {
+ ERR_FAIL_COND(page_pool == nullptr); //sanity check
+
+ _grow_page_array(); //keep out of inline
+ }
+
+ uint32_t page_id = page_pool->alloc_page();
+ page_data[page_count] = page_pool->get_page(page_id);
+ page_ids[page_count] = page_id;
+ }
+
+ // place the new value
+ uint32_t page = count >> page_size_shift;
+ uint32_t offset = count & page_size_mask;
+
+ if (!__has_trivial_constructor(T)) {
+ memnew_placement(&page_data[page][offset], T(p_value));
+ } else {
+ page_data[page][offset] = p_value;
+ }
+
+ count++;
+ }
+
+ _FORCE_INLINE_ void pop_back() {
+ ERR_FAIL_COND(count == 0);
+
+ if (!__has_trivial_destructor(T)) {
+ uint32_t page = (count - 1) >> page_size_shift;
+ uint32_t offset = (count - 1) & page_size_mask;
+ page_data[page][offset].~T();
+ }
+
+ uint32_t remainder = count & page_size_mask;
+ if (unlikely(remainder == 1)) {
+ // one element remained, so page must be freed.
+ uint32_t last_page = _get_pages_in_use() - 1;
+ page_pool->free_page(page_ids[last_page]);
+ }
+ count--;
+ }
+
+ void clear() {
+ //destruct if needed
+ if (!__has_trivial_destructor(T)) {
+ for (uint64_t i = 0; i < count; i++) {
+ uint32_t page = i >> page_size_shift;
+ uint32_t offset = i & page_size_mask;
+ page_data[page][offset].~T();
+ }
+ }
+
+ //return the pages to the pagepool, so they can be used by another array eventually
+ uint32_t pages_used = _get_pages_in_use();
+ for (uint32_t i = 0; i < pages_used; i++) {
+ page_pool->free_page(page_ids[i]);
+ }
+
+ count = 0;
+
+ //note we leave page_data and page_indices intact for next use. If you really want to clear them call reset()
+ }
+
+ void reset() {
+ clear();
+ if (page_data) {
+ memfree(page_data);
+ memfree(page_ids);
+ page_data = nullptr;
+ page_ids = nullptr;
+ max_pages_used = 0;
+ }
+ }
+
+ // This takes the pages from a source array and merges them to this one
+ // resulting order is undefined, but content is merged very efficiently,
+ // making it ideal to fill content on several threads to later join it.
+
+ void merge_unordered(PagedArray<T> &p_array) {
+ ERR_FAIL_COND(page_pool != p_array.page_pool);
+
+ uint32_t remainder = count & page_size_mask;
+
+ T *remainder_page = nullptr;
+ uint32_t remainder_page_id;
+
+ if (remainder > 0) {
+ uint32_t last_page = _get_pages_in_use() - 1;
+ remainder_page = page_data[last_page];
+ remainder_page_id = page_ids[last_page];
+ }
+
+ count -= remainder;
+
+ uint32_t src_pages = p_array._get_pages_in_use();
+ uint32_t page_size = page_size_mask + 1;
+
+ for (uint32_t i = 0; i < src_pages; i++) {
+ uint32_t page_count = _get_pages_in_use();
+ uint32_t new_page_count = page_count + 1;
+
+ if (unlikely(new_page_count > max_pages_used)) {
+ _grow_page_array(); //keep out of inline
+ }
+
+ page_data[page_count] = p_array.page_data[i];
+ page_ids[page_count] = p_array.page_ids[i];
+ if (i == src_pages - 1) {
+ //last page, only increment with remainder
+ count += p_array.count & page_size_mask;
+ } else {
+ count += page_size;
+ }
+ }
+ p_array.count = 0; //take away the other array pages
+
+ //handle the remainder page if exists
+ if (remainder_page) {
+ uint32_t new_remainder = count & page_size_mask;
+
+ if (new_remainder > 0) {
+ //must merge old remainder with new remainder
+
+ T *dst_page = page_data[_get_pages_in_use() - 1];
+ uint32_t to_copy = MIN(page_size - new_remainder, remainder);
+
+ for (uint32_t i = 0; i < to_copy; i++) {
+ if (!__has_trivial_constructor(T)) {
+ memnew_placement(&dst_page[i + new_remainder], T(remainder_page[i + remainder - to_copy]));
+ } else {
+ dst_page[i + new_remainder] = remainder_page[i + remainder - to_copy];
+ }
+
+ if (!__has_trivial_destructor(T)) {
+ remainder_page[i + remainder - to_copy].~T();
+ }
+ }
+
+ remainder -= to_copy; //subtract what was copied from remainder
+ count += to_copy; //add what was copied to the count
+
+ if (remainder == 0) {
+ //entire remainder copied, let go of remainder page
+ page_pool->free_page(remainder_page_id);
+ remainder_page = nullptr;
+ }
+ }
+
+ if (remainder > 0) {
+ //there is still remainder, append it
+ uint32_t page_count = _get_pages_in_use();
+ uint32_t new_page_count = page_count + 1;
+
+ if (unlikely(new_page_count > max_pages_used)) {
+ _grow_page_array(); //keep out of inline
+ }
+
+ page_data[page_count] = remainder_page;
+ page_ids[page_count] = remainder_page_id;
+
+ count += remainder;
+ }
+ }
+ }
+
+ _FORCE_INLINE_ uint64_t size() const {
+ return count;
+ }
+
+ void set_page_pool(PagedArrayPool<T> *p_page_pool) {
+ ERR_FAIL_COND(max_pages_used > 0); //sanity check
+
+ page_pool = p_page_pool;
+ page_size_mask = page_pool->get_page_size_mask();
+ page_size_shift = page_pool->get_page_size_shift();
+ }
+
+ ~PagedArray() {
+ reset();
+ }
+};
+
+#endif // PAGED_ARRAY_H
diff --git a/core/templates/pair.h b/core/templates/pair.h
index 89ea2b9fd9..bc1a764694 100644
--- a/core/templates/pair.h
+++ b/core/templates/pair.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/pass_func.h b/core/templates/pass_func.h
index a074ad190d..d2f465e91c 100644
--- a/core/templates/pass_func.h
+++ b/core/templates/pass_func.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/rid.h b/core/templates/rid.h
index a475d166d5..4c7119b4ea 100644
--- a/core/templates/rid.h
+++ b/core/templates/rid.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,30 +40,37 @@ class RID {
uint64_t _id = 0;
public:
- _FORCE_INLINE_ bool operator==(const RID &p_rid) const {
+ _ALWAYS_INLINE_ bool operator==(const RID &p_rid) const {
return _id == p_rid._id;
}
- _FORCE_INLINE_ bool operator<(const RID &p_rid) const {
+ _ALWAYS_INLINE_ bool operator<(const RID &p_rid) const {
return _id < p_rid._id;
}
- _FORCE_INLINE_ bool operator<=(const RID &p_rid) const {
+ _ALWAYS_INLINE_ bool operator<=(const RID &p_rid) const {
return _id <= p_rid._id;
}
- _FORCE_INLINE_ bool operator>(const RID &p_rid) const {
+ _ALWAYS_INLINE_ bool operator>(const RID &p_rid) const {
return _id > p_rid._id;
}
- _FORCE_INLINE_ bool operator>=(const RID &p_rid) const {
+ _ALWAYS_INLINE_ bool operator>=(const RID &p_rid) const {
return _id >= p_rid._id;
}
- _FORCE_INLINE_ bool operator!=(const RID &p_rid) const {
+ _ALWAYS_INLINE_ bool operator!=(const RID &p_rid) const {
return _id != p_rid._id;
}
- _FORCE_INLINE_ bool is_valid() const { return _id != 0; }
- _FORCE_INLINE_ bool is_null() const { return _id == 0; }
+ _ALWAYS_INLINE_ bool is_valid() const { return _id != 0; }
+ _ALWAYS_INLINE_ bool is_null() const { return _id == 0; }
- _FORCE_INLINE_ uint64_t get_id() const { return _id; }
+ _ALWAYS_INLINE_ uint32_t get_local_index() const { return _id & 0xFFFFFFFF; }
- _FORCE_INLINE_ RID() {}
+ static _ALWAYS_INLINE_ RID from_uint64(uint64_t p_id) {
+ RID _rid;
+ _rid._id = p_id;
+ return _rid;
+ }
+ _ALWAYS_INLINE_ uint64_t get_id() const { return _id; }
+
+ _ALWAYS_INLINE_ RID() {}
};
#endif // RID_H
diff --git a/core/templates/rid_owner.cpp b/core/templates/rid_owner.cpp
index a5065f29f8..56f39ab779 100644
--- a/core/templates/rid_owner.cpp
+++ b/core/templates/rid_owner.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -30,4 +30,4 @@
#include "rid_owner.h"
-volatile uint64_t RID_AllocBase::base_id = 1;
+SafeNumeric<uint64_t> RID_AllocBase::base_id{ 1 };
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index d1bcb92010..c4aa93c394 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -44,7 +44,7 @@
#include <typeinfo>
class RID_AllocBase {
- static volatile uint64_t base_id;
+ static SafeNumeric<uint64_t> base_id;
protected:
static RID _make_from_id(uint64_t p_id) {
@@ -54,7 +54,7 @@ protected:
}
static uint64_t _gen_id() {
- return atomic_increment(&base_id);
+ return base_id.increment();
}
static RID _gen_rid() {
@@ -79,8 +79,7 @@ class RID_Alloc : public RID_AllocBase {
SpinLock spin_lock;
-public:
- RID make_rid(const T &p_value) {
+ _FORCE_INLINE_ RID _allocate_rid(const T *p_initializer) {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -115,15 +114,22 @@ public:
uint32_t free_chunk = free_index / elements_in_chunk;
uint32_t free_element = free_index % elements_in_chunk;
- T *ptr = &chunks[free_chunk][free_element];
- memnew_placement(ptr, T(p_value));
+ if (p_initializer) {
+ T *ptr = &chunks[free_chunk][free_element];
+ memnew_placement(ptr, T(*p_initializer));
+ }
- uint32_t validator = (uint32_t)(_gen_id() & 0xFFFFFFFF);
+ uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF);
uint64_t id = validator;
id <<= 32;
id |= free_index;
validator_chunks[free_chunk][free_element] = validator;
+
+ if (!p_initializer) {
+ validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit
+ }
+
alloc_count++;
if (THREAD_SAFE) {
@@ -133,7 +139,20 @@ public:
return _make_from_id(id);
}
- _FORCE_INLINE_ T *getornull(const RID &p_rid) {
+public:
+ RID make_rid(const T &p_value) {
+ return _allocate_rid(&p_value);
+ }
+
+ //allocate but don't initialize, use initialize_rid afterwards
+ RID allocate_rid() {
+ return _allocate_rid(nullptr);
+ }
+
+ _FORCE_INLINE_ T *getornull(const RID &p_rid, bool p_initialize = false) {
+ if (p_rid == RID()) {
+ return nullptr;
+ }
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -151,10 +170,32 @@ public:
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
- if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+
+ if (unlikely(p_initialize)) {
+ if (unlikely(!(validator_chunks[idx_chunk][idx_element] & 0x80000000))) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_V_MSG(nullptr, "Initializing already initialized RID");
+ }
+
+ if (unlikely((validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) != validator)) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_V_MSG(nullptr, "Attempting to initialize the wrong RID");
+ return nullptr;
+ }
+
+ validator_chunks[idx_chunk][idx_element] &= 0x7FFFFFFF; //initialized
+
+ } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
+ if (validator_chunks[idx_chunk][idx_element] & 0x80000000) {
+ ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID");
+ }
return nullptr;
}
@@ -166,6 +207,11 @@ public:
return ptr;
}
+ void initialize_rid(RID p_rid, const T &p_value) {
+ T *mem = getornull(p_rid, true);
+ ERR_FAIL_COND(!mem);
+ memnew_placement(mem, T(p_value));
+ }
_FORCE_INLINE_ bool owns(const RID &p_rid) {
if (THREAD_SAFE) {
@@ -186,7 +232,7 @@ public:
uint32_t validator = uint32_t(id >> 32);
- bool owned = validator_chunks[idx_chunk][idx_element] == validator;
+ bool owned = (validator_chunks[idx_chunk][idx_element] & 0x7FFFFFFF) == validator;
if (THREAD_SAFE) {
spin_lock.unlock();
@@ -213,7 +259,12 @@ public:
uint32_t idx_element = idx % elements_in_chunk;
uint32_t validator = uint32_t(id >> 32);
- if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
+ if (unlikely(validator_chunks[idx_chunk][idx_element] & 0x80000000)) {
+ if (THREAD_SAFE) {
+ spin_lock.unlock();
+ }
+ ERR_FAIL_MSG("Attempted to free an uninitialized or invalid RID");
+ } else if (unlikely(validator_chunks[idx_chunk][idx_element] != validator)) {
if (THREAD_SAFE) {
spin_lock.unlock();
}
@@ -330,6 +381,14 @@ public:
return alloc.make_rid(p_ptr);
}
+ _FORCE_INLINE_ RID allocate_rid() {
+ return alloc.allocate_rid();
+ }
+
+ _FORCE_INLINE_ void initialize_rid(RID p_rid, T *p_ptr) {
+ alloc.initialize_rid(p_rid, p_ptr);
+ }
+
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
T **ptr = alloc.getornull(p_rid);
if (unlikely(!ptr)) {
@@ -338,6 +397,12 @@ public:
return *ptr;
}
+ _FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
+ T **ptr = alloc.getornull(p_rid);
+ ERR_FAIL_COND(!ptr);
+ *ptr = p_new_ptr;
+ }
+
_FORCE_INLINE_ bool owns(const RID &p_rid) {
return alloc.owns(p_rid);
}
@@ -346,6 +411,18 @@ public:
alloc.free(p_rid);
}
+ _FORCE_INLINE_ uint32_t get_rid_count() const {
+ return alloc.get_rid_count();
+ }
+
+ _FORCE_INLINE_ RID get_rid_by_index(uint32_t p_index) {
+ return alloc.get_rid_by_index(p_index);
+ }
+
+ _FORCE_INLINE_ T *get_ptr_by_index(uint32_t p_index) {
+ return *alloc.get_ptr_by_index(p_index);
+ }
+
_FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
return alloc.get_owned_list(p_owned);
}
@@ -353,6 +430,7 @@ public:
void set_description(const char *p_descrption) {
alloc.set_description(p_descrption);
}
+
RID_PtrOwner(uint32_t p_target_chunk_byte_size = 4096) :
alloc(p_target_chunk_byte_size) {}
};
@@ -366,6 +444,14 @@ public:
return alloc.make_rid(p_ptr);
}
+ _FORCE_INLINE_ RID allocate_rid() {
+ return alloc.allocate_rid();
+ }
+
+ _FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) {
+ alloc.initialize_rid(p_rid, p_ptr);
+ }
+
_FORCE_INLINE_ T *getornull(const RID &p_rid) {
return alloc.getornull(p_rid);
}
diff --git a/core/templates/ring_buffer.h b/core/templates/ring_buffer.h
index 12ec047fb6..e7b77440f1 100644
--- a/core/templates/ring_buffer.h
+++ b/core/templates/ring_buffer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/safe_refcount.cpp b/core/templates/safe_refcount.cpp
deleted file mode 100644
index d5ee778ef7..0000000000
--- a/core/templates/safe_refcount.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*************************************************************************/
-/* safe_refcount.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 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 "safe_refcount.h"
-
-#if defined(_MSC_VER)
-
-/* Implementation for MSVC-Windows */
-
-// don't pollute my namespace!
-#include <windows.h>
-
-#define ATOMIC_CONDITIONAL_INCREMENT_BODY(m_pw, m_win_type, m_win_cmpxchg, m_cpp_type) \
- /* try to increment until it actually works */ \
- /* taken from boost */ \
- while (true) { \
- m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
- if (tmp == 0) { \
- return 0; /* if zero, can't add to it anymore */ \
- } \
- if (m_win_cmpxchg((m_win_type volatile *)(m_pw), tmp + 1, tmp) == tmp) { \
- return tmp + 1; \
- } \
- }
-
-#define ATOMIC_EXCHANGE_IF_GREATER_BODY(m_pw, m_val, m_win_type, m_win_cmpxchg, m_cpp_type) \
- while (true) { \
- m_cpp_type tmp = static_cast<m_cpp_type const volatile &>(*(m_pw)); \
- if (tmp >= m_val) { \
- return tmp; /* already greater, or equal */ \
- } \
- if (m_win_cmpxchg((m_win_type volatile *)(m_pw), m_val, tmp) == tmp) { \
- return m_val; \
- } \
- }
-
-_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw) {
- ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
- return InterlockedDecrement((LONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
- return InterlockedIncrement((LONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
- return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
- return InterlockedAdd((LONG volatile *)pw, val);
-}
-
-_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val) {
- ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw) {
- ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
- return InterlockedDecrement64((LONGLONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
- return InterlockedIncrement64((LONGLONG volatile *)pw);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
- return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
- return InterlockedAdd64((LONGLONG volatile *)pw, val);
-}
-
-_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val) {
- ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t);
-}
-
-// The actual advertised functions; they'll call the right implementation
-
-uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
- return _atomic_conditional_increment_impl(pw);
-}
-
-uint32_t atomic_decrement(volatile uint32_t *pw) {
- return _atomic_decrement_impl(pw);
-}
-
-uint32_t atomic_increment(volatile uint32_t *pw) {
- return _atomic_increment_impl(pw);
-}
-
-uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
- return _atomic_sub_impl(pw, val);
-}
-
-uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
- return _atomic_add_impl(pw, val);
-}
-
-uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
- return _atomic_exchange_if_greater_impl(pw, val);
-}
-
-uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
- return _atomic_conditional_increment_impl(pw);
-}
-
-uint64_t atomic_decrement(volatile uint64_t *pw) {
- return _atomic_decrement_impl(pw);
-}
-
-uint64_t atomic_increment(volatile uint64_t *pw) {
- return _atomic_increment_impl(pw);
-}
-
-uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
- return _atomic_sub_impl(pw, val);
-}
-
-uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
- return _atomic_add_impl(pw, val);
-}
-
-uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
- return _atomic_exchange_if_greater_impl(pw, val);
-}
-#endif
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index 6b08b876f8..91a34ecd54 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -31,167 +31,291 @@
#ifndef SAFE_REFCOUNT_H
#define SAFE_REFCOUNT_H
-#include "core/os/mutex.h"
#include "core/typedefs.h"
-#include "platform_config.h"
-// Atomic functions, these are used for multithread safe reference counters!
+#if !defined(NO_THREADS)
-#ifdef NO_THREADS
+#include <atomic>
-/* Bogus implementation unaware of multiprocessing */
+// Design goals for these classes:
+// - No automatic conversions or arithmetic operators,
+// to keep explicit the use of atomics everywhere.
+// - Using acquire-release semantics, even to set the first value.
+// The first value may be set relaxedly in many cases, but adding the distinction
+// between relaxed and unrelaxed operation to the interface would make it needlessly
+// flexible. There's negligible waste in having release semantics for the initial
+// value and, as an important benefit, you can be sure the value is properly synchronized
+// even with threads that are already running.
+
+// This is used in very specific areas of the engine where it's critical that these guarantees are held
+#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
+ static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type)); \
+ static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type)); \
+ static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value);
template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
- if (*pw == 0) {
- return 0;
+class SafeNumeric {
+ std::atomic<T> value;
+
+ static_assert(std::atomic<T>::is_always_lock_free);
+
+public:
+ _ALWAYS_INLINE_ void set(T p_value) {
+ value.store(p_value, std::memory_order_release);
}
- (*pw)++;
+ _ALWAYS_INLINE_ T get() const {
+ return value.load(std::memory_order_acquire);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T increment() {
+ return value.fetch_add(1, std::memory_order_acq_rel) + 1;
+ }
-template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
- (*pw)--;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postincrement() {
+ return value.fetch_add(1, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T decrement() {
+ return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
+ }
-template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
- (*pw)++;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postdecrement() {
+ return value.fetch_sub(1, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T add(T p_value) {
+ return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
+ }
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
- (*pw) -= val;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postadd(T p_value) {
+ return value.fetch_add(p_value, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T sub(T p_value) {
+ return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
+ }
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
- (*pw) += val;
+ // Returns the original value instead of the new one
+ _ALWAYS_INLINE_ T postsub(T p_value) {
+ return value.fetch_sub(p_value, std::memory_order_acq_rel);
+ }
- return *pw;
-}
+ _ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+ while (true) {
+ T tmp = value.load(std::memory_order_acquire);
+ if (tmp >= p_value) {
+ return tmp; // already greater, or equal
+ }
+ if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
+ return p_value;
+ }
+ }
+ }
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
- if (val > *pw) {
- *pw = val;
+ _ALWAYS_INLINE_ T conditional_increment() {
+ while (true) {
+ T c = value.load(std::memory_order_acquire);
+ if (c == 0) {
+ return 0;
+ }
+ if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
+ return c + 1;
+ }
+ }
}
- return *pw;
-}
+ _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
+ set(p_value);
+ }
+};
-#elif defined(__GNUC__)
+class SafeFlag {
+ std::atomic_bool flag;
-/* Implementation for GCC & Clang */
+ static_assert(std::atomic_bool::is_always_lock_free);
-// GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes.
-// Clang states it supports GCC atomic builtins.
+public:
+ _ALWAYS_INLINE_ bool is_set() const {
+ return flag.load(std::memory_order_acquire);
+ }
-template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
- while (true) {
- T tmp = static_cast<T const volatile &>(*pw);
- if (tmp == 0) {
- return 0; // if zero, can't add to it anymore
- }
- if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp) {
- return tmp + 1;
- }
+ _ALWAYS_INLINE_ void set() {
+ flag.store(true, std::memory_order_release);
}
-}
-template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
- return __sync_sub_and_fetch(pw, 1);
-}
+ _ALWAYS_INLINE_ void clear() {
+ flag.store(false, std::memory_order_release);
+ }
+
+ _ALWAYS_INLINE_ void set_to(bool p_value) {
+ flag.store(p_value, std::memory_order_release);
+ }
+
+ _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
+ set_to(p_value);
+ }
+};
+
+class SafeRefCount {
+ SafeNumeric<uint32_t> count;
+
+public:
+ _ALWAYS_INLINE_ bool ref() { // true on success
+ return count.conditional_increment() != 0;
+ }
+
+ _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+ return count.conditional_increment();
+ }
+
+ _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+ return count.decrement() == 0;
+ }
+
+ _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+ return count.decrement();
+ }
+
+ _ALWAYS_INLINE_ uint32_t get() const {
+ return count.get();
+ }
+
+ _ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
+ count.set(p_value);
+ }
+};
+
+#else
template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
- return __sync_add_and_fetch(pw, 1);
-}
-
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
- return __sync_sub_and_fetch(pw, val);
-}
-
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
- return __sync_add_and_fetch(pw, val);
-}
-
-template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
- while (true) {
- T tmp = static_cast<T const volatile &>(*pw);
- if (tmp >= val) {
- return tmp; // already greater, or equal
+class SafeNumeric {
+protected:
+ T value;
+
+public:
+ _ALWAYS_INLINE_ void set(T p_value) {
+ value = p_value;
+ }
+
+ _ALWAYS_INLINE_ T get() const {
+ return value;
+ }
+
+ _ALWAYS_INLINE_ T increment() {
+ return ++value;
+ }
+
+ _ALWAYS_INLINE_ T postincrement() {
+ return value++;
+ }
+
+ _ALWAYS_INLINE_ T decrement() {
+ return --value;
+ }
+
+ _ALWAYS_INLINE_ T postdecrement() {
+ return value--;
+ }
+
+ _ALWAYS_INLINE_ T add(T p_value) {
+ return value += p_value;
+ }
+
+ _ALWAYS_INLINE_ T postadd(T p_value) {
+ T old = value;
+ value += p_value;
+ return old;
+ }
+
+ _ALWAYS_INLINE_ T sub(T p_value) {
+ return value -= p_value;
+ }
+
+ _ALWAYS_INLINE_ T postsub(T p_value) {
+ T old = value;
+ value -= p_value;
+ return old;
+ }
+
+ _ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
+ if (value < p_value) {
+ value = p_value;
}
- if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) {
- return val;
+ return value;
+ }
+
+ _ALWAYS_INLINE_ T conditional_increment() {
+ if (value == 0) {
+ return 0;
+ } else {
+ return ++value;
}
}
-}
-
-#elif defined(_MSC_VER)
-// For MSVC use a separate compilation unit to prevent windows.h from polluting
-// the global namespace.
-uint32_t atomic_conditional_increment(volatile uint32_t *pw);
-uint32_t atomic_decrement(volatile uint32_t *pw);
-uint32_t atomic_increment(volatile uint32_t *pw);
-uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val);
-uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val);
-uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val);
-
-uint64_t atomic_conditional_increment(volatile uint64_t *pw);
-uint64_t atomic_decrement(volatile uint64_t *pw);
-uint64_t atomic_increment(volatile uint64_t *pw);
-uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val);
-uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val);
-uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val);
-#else
-//no threads supported?
-#error Must provide atomic functions for this platform or compiler!
-#endif
+ _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
+ value(p_value) {
+ }
+};
-struct SafeRefCount {
- uint32_t count = 0;
+class SafeFlag {
+protected:
+ bool flag;
public:
- // destroy() is called when weak_count_ drops to zero.
-
- _ALWAYS_INLINE_ bool ref() { // true on success
+ _ALWAYS_INLINE_ bool is_set() const {
+ return flag;
+ }
- return atomic_conditional_increment(&count) != 0;
+ _ALWAYS_INLINE_ void set() {
+ flag = true;
}
- _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+ _ALWAYS_INLINE_ void clear() {
+ flag = false;
+ }
- return atomic_conditional_increment(&count);
+ _ALWAYS_INLINE_ void set_to(bool p_value) {
+ flag = p_value;
}
- _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+ _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
+ flag(p_value) {}
+};
+
+class SafeRefCount {
+ uint32_t count = 0;
- return atomic_decrement(&count) == 0;
+public:
+ _ALWAYS_INLINE_ bool ref() { // true on success
+ if (count != 0) {
+ ++count;
+ return true;
+ } else {
+ return false;
+ }
}
- _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+ _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
+ if (count != 0) {
+ return ++count;
+ } else {
+ return 0;
+ }
+ }
- return atomic_decrement(&count);
+ _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
+ return --count == 0;
}
- _ALWAYS_INLINE_ uint32_t get() const { // nothrow
+ _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
+ return --count;
+ }
+ _ALWAYS_INLINE_ uint32_t get() const {
return count;
}
@@ -200,4 +324,6 @@ public:
}
};
+#endif
+
#endif // SAFE_REFCOUNT_H
diff --git a/core/templates/self_list.h b/core/templates/self_list.h
index 2a037d109c..e8d36ea358 100644
--- a/core/templates/self_list.h
+++ b/core/templates/self_list.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/set.h b/core/templates/set.h
index d0ac71a710..3036ecf27d 100644
--- a/core/templates/set.h
+++ b/core/templates/set.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -576,7 +576,7 @@ public:
return e;
}
- inline bool empty() const { return _data.size_cache == 0; }
+ inline bool is_empty() const { return _data.size_cache == 0; }
inline int size() const { return _data.size_cache; }
int calculate_depth() const {
diff --git a/core/templates/simple_type.h b/core/templates/simple_type.h
index 841ab9f384..80bfa83fde 100644
--- a/core/templates/simple_type.h
+++ b/core/templates/simple_type.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/sort_array.h b/core/templates/sort_array.h
index ece5e72e51..1656d2991d 100644
--- a/core/templates/sort_array.h
+++ b/core/templates/sort_array.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/templates/thread_work_pool.cpp b/core/templates/thread_work_pool.cpp
index 3a95e83ffc..17969a2c90 100644
--- a/core/templates/thread_work_pool.cpp
+++ b/core/templates/thread_work_pool.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -32,14 +32,15 @@
#include "core/os/os.h"
-void ThreadWorkPool::_thread_function(ThreadData *p_thread) {
+void ThreadWorkPool::_thread_function(void *p_user) {
+ ThreadData *thread = static_cast<ThreadData *>(p_user);
while (true) {
- p_thread->start.wait();
- if (p_thread->exit.load()) {
+ thread->start.wait();
+ if (thread->exit.load()) {
break;
}
- p_thread->work->work();
- p_thread->completed.post();
+ thread->work->work();
+ thread->completed.post();
}
}
@@ -54,7 +55,7 @@ void ThreadWorkPool::init(int p_thread_count) {
for (uint32_t i = 0; i < thread_count; i++) {
threads[i].exit.store(false);
- threads[i].thread = memnew(std::thread(ThreadWorkPool::_thread_function, &threads[i]));
+ threads[i].thread.start(&ThreadWorkPool::_thread_function, &threads[i]);
}
}
@@ -68,8 +69,7 @@ void ThreadWorkPool::finish() {
threads[i].start.post();
}
for (uint32_t i = 0; i < thread_count; i++) {
- threads[i].thread->join();
- memdelete(threads[i].thread);
+ threads[i].thread.wait_to_finish();
}
memdelete_arr(threads);
diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h
index e083cdcb24..19ab1dda3a 100644
--- a/core/templates/thread_work_pool.h
+++ b/core/templates/thread_work_pool.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -33,9 +33,9 @@
#include "core/os/memory.h"
#include "core/os/semaphore.h"
+#include "core/os/thread.h"
#include <atomic>
-#include <thread>
class ThreadWorkPool {
std::atomic<uint32_t> index;
@@ -64,7 +64,7 @@ class ThreadWorkPool {
};
struct ThreadData {
- std::thread *thread;
+ Thread thread;
Semaphore start;
Semaphore completed;
std::atomic<bool> exit;
@@ -75,7 +75,7 @@ class ThreadWorkPool {
uint32_t thread_count = 0;
BaseWork *current_work = nullptr;
- static void _thread_function(ThreadData *p_thread);
+ static void _thread_function(void *p_user);
public:
template <class C, class M, class U>
@@ -125,6 +125,7 @@ public:
end_work();
}
+ _FORCE_INLINE_ int get_thread_count() const { return thread_count; }
void init(int p_thread_count = -1);
void finish();
~ThreadWorkPool();
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 9d45f7c30a..6a8902707c 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -79,7 +79,7 @@ public:
_FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); }
_FORCE_INLINE_ void clear() { resize(0); }
- _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); }
+ _FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
_FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); }
_FORCE_INLINE_ const T &get(int p_index) const { return _cowdata.get(p_index); }
@@ -112,6 +112,10 @@ public:
sort_custom<_DefaultComparator<T>>();
}
+ Vector<T> duplicate() {
+ return *this;
+ }
+
void ordered_insert(const T &p_val) {
int i;
for (i = 0; i < _cowdata.size(); i++) {
diff --git a/core/templates/vmap.h b/core/templates/vmap.h
index 8d2a3d2a9c..520e0b3720 100644
--- a/core/templates/vmap.h
+++ b/core/templates/vmap.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -54,7 +54,7 @@ private:
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
r_exact = false;
- if (_cowdata.empty()) {
+ if (_cowdata.is_empty()) {
return 0;
}
@@ -89,7 +89,7 @@ private:
}
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
- if (_cowdata.empty()) {
+ if (_cowdata.is_empty()) {
return -1;
}
@@ -147,7 +147,7 @@ public:
}
_FORCE_INLINE_ int size() const { return _cowdata.size(); }
- _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); }
+ _FORCE_INLINE_ bool is_empty() const { return _cowdata.is_empty(); }
const Pair *get_array() const {
return _cowdata.ptr();
diff --git a/core/templates/vset.h b/core/templates/vset.h
index 4c0b8717b6..6665651d42 100644
--- a/core/templates/vset.h
+++ b/core/templates/vset.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,7 +40,7 @@ class VSet {
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
r_exact = false;
- if (_data.empty()) {
+ if (_data.is_empty()) {
return 0;
}
@@ -76,7 +76,7 @@ class VSet {
}
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
- if (_data.empty()) {
+ if (_data.is_empty()) {
return -1;
}
@@ -126,7 +126,7 @@ public:
return _find_exact(p_val);
}
- _FORCE_INLINE_ bool empty() const { return _data.empty(); }
+ _FORCE_INLINE_ bool is_empty() const { return _data.is_empty(); }
_FORCE_INLINE_ int size() const { return _data.size(); }
diff --git a/core/typedefs.h b/core/typedefs.h
index 7c98bc37f7..cdbfb34e56 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 5043868b1d..9a2922a777 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -35,6 +35,7 @@
#include "core/object/script_language.h"
#include "core/templates/hashfuncs.h"
#include "core/templates/vector.h"
+#include "core/variant/callable.h"
#include "core/variant/variant.h"
class ArrayPrivate {
@@ -86,8 +87,8 @@ int Array::size() const {
return _p->array.size();
}
-bool Array::empty() const {
- return _p->array.empty();
+bool Array::is_empty() const {
+ return _p->array.is_empty();
}
void Array::clear() {
@@ -318,7 +319,7 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const { // l
ERR_FAIL_COND_V_MSG(p_step == 0, new_arr, "Array slice step size cannot be zero.");
- if (empty()) { // Don't try to slice empty arrays.
+ if (is_empty()) { // Don't try to slice empty arrays.
return new_arr;
}
if (p_step > 0) {
@@ -371,25 +372,22 @@ void Array::sort() {
}
struct _ArrayVariantSortCustom {
- Object *obj = nullptr;
- StringName func;
+ Callable func;
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
const Variant *args[2] = { &p_l, &p_r };
Callable::CallError err;
- bool res = obj->call(func, args, 2, err);
- if (err.error != Callable::CallError::CALL_OK) {
- res = false;
- }
+ Variant res;
+ func.call(args, 2, res, err);
+ ERR_FAIL_COND_V_MSG(err.error != Callable::CallError::CALL_OK, false,
+ "Error calling sorting method: " + Variant::get_callable_error_text(func, args, 1, err));
return res;
}
};
-void Array::sort_custom(Object *p_obj, const StringName &p_function) {
- ERR_FAIL_NULL(p_obj);
+void Array::sort_custom(Callable p_callable) {
SortArray<Variant, _ArrayVariantSortCustom, true> avs;
- avs.compare.obj = p_obj;
- avs.compare.func = p_function;
+ avs.compare.func = p_callable;
avs.sort(_p->array.ptrw(), _p->array.size());
}
@@ -438,13 +436,11 @@ int Array::bsearch(const Variant &p_value, bool p_before) {
return bisect(_p->array, p_value, p_before, _ArrayVariantSort());
}
-int Array::bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before) {
+int Array::bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before) {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "custom binary search"), -1);
- ERR_FAIL_NULL_V(p_obj, 0);
_ArrayVariantSortCustom less;
- less.obj = p_obj;
- less.func = p_function;
+ less.func = p_callable;
return bisect(_p->array, p_value, p_before, less);
}
@@ -459,7 +455,7 @@ void Array::push_front(const Variant &p_value) {
}
Variant Array::pop_back() {
- if (!_p->array.empty()) {
+ if (!_p->array.is_empty()) {
int n = _p->array.size() - 1;
Variant ret = _p->array.get(n);
_p->array.resize(n);
@@ -469,7 +465,7 @@ Variant Array::pop_back() {
}
Variant Array::pop_front() {
- if (!_p->array.empty()) {
+ if (!_p->array.is_empty()) {
Variant ret = _p->array.get(0);
_p->array.remove(0);
return ret;
diff --git a/core/variant/array.h b/core/variant/array.h
index e01ac13168..d8f2402330 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -37,6 +37,7 @@ class Variant;
class ArrayPrivate;
class Object;
class StringName;
+class Callable;
class Array {
mutable ArrayPrivate *_p;
@@ -57,7 +58,7 @@ public:
const Variant &get(int p_idx) const;
int size() const;
- bool empty() const;
+ bool is_empty() const;
void clear();
bool operator==(const Array &p_array) const;
@@ -78,10 +79,10 @@ public:
Variant back() const;
void sort();
- void sort_custom(Object *p_obj, const StringName &p_function);
+ void sort_custom(Callable p_callable);
void shuffle();
int bsearch(const Variant &p_value, bool p_before = true);
- int bsearch_custom(const Variant &p_value, Object *p_obj, const StringName &p_function, bool p_before = true);
+ int bsearch_custom(const Variant &p_value, Callable p_callable, bool p_before = true);
void invert();
int find(const Variant &p_value, int p_from = 0) const;
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index e950709526..490bd45b7b 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -87,7 +87,8 @@ VARIANT_ENUM_CAST(Object::ConnectFlags);
VARIANT_ENUM_CAST(Vector3::Axis);
VARIANT_ENUM_CAST(Error);
-VARIANT_ENUM_CAST(Margin);
+VARIANT_ENUM_CAST(Side);
+VARIANT_ENUM_CAST(ClockDirection);
VARIANT_ENUM_CAST(Corner);
VARIANT_ENUM_CAST(Orientation);
VARIANT_ENUM_CAST(HAlign);
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index e504fd05e3..bd51e2dd1e 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 9334ae3581..090fd888e2 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/callable_bind.cpp b/core/variant/callable_bind.cpp
index da08d3ccbd..10446a5ec1 100644
--- a/core/variant/callable_bind.cpp
+++ b/core/variant/callable_bind.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/callable_bind.h b/core/variant/callable_bind.h
index fc5659e412..feb40d1de9 100644
--- a/core/variant/callable_bind.h
+++ b/core/variant/callable_bind.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index 4d3a5f683b..f13a37cddd 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index 2bc1f7a86d..b2f7c6aa0a 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -40,7 +40,7 @@ struct DictionaryPrivate {
};
void Dictionary::get_key_list(List<Variant> *p_keys) const {
- if (_p->variant_map.empty()) {
+ if (_p->variant_map.is_empty()) {
return;
}
@@ -121,7 +121,7 @@ int Dictionary::size() const {
return _p->variant_map.size();
}
-bool Dictionary::empty() const {
+bool Dictionary::is_empty() const {
return !_p->variant_map.size();
}
@@ -192,7 +192,7 @@ uint32_t Dictionary::hash() const {
Array Dictionary::keys() const {
Array varr;
- if (_p->variant_map.empty()) {
+ if (_p->variant_map.is_empty()) {
return varr;
}
@@ -209,7 +209,7 @@ Array Dictionary::keys() const {
Array Dictionary::values() const {
Array varr;
- if (_p->variant_map.empty()) {
+ if (_p->variant_map.is_empty()) {
return varr;
}
diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h
index bbe94122ad..4067ff9fd9 100644
--- a/core/variant/dictionary.h
+++ b/core/variant/dictionary.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -60,7 +60,7 @@ public:
Variant get(const Variant &p_key, const Variant &p_default) const;
int size() const;
- bool empty() const;
+ bool is_empty() const;
void clear();
bool has(const Variant &p_key) const;
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index 40fa3543dc..c294592b63 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -100,6 +100,7 @@ struct PtrToArg {};
}
MAKE_PTRARG(bool);
+// Integer types.
MAKE_PTRARGCONV(uint8_t, int64_t);
MAKE_PTRARGCONV(int8_t, int64_t);
MAKE_PTRARGCONV(uint16_t, int64_t);
@@ -108,15 +109,16 @@ MAKE_PTRARGCONV(uint32_t, int64_t);
MAKE_PTRARGCONV(int32_t, int64_t);
MAKE_PTRARG(int64_t);
MAKE_PTRARG(uint64_t);
+// Float types
MAKE_PTRARGCONV(float, double);
MAKE_PTRARG(double);
MAKE_PTRARG(String);
MAKE_PTRARG(Vector2);
-MAKE_PTRARG(Rect2);
-MAKE_PTRARG_BY_REFERENCE(Vector3);
MAKE_PTRARG(Vector2i);
+MAKE_PTRARG(Rect2);
MAKE_PTRARG(Rect2i);
+MAKE_PTRARG_BY_REFERENCE(Vector3);
MAKE_PTRARG_BY_REFERENCE(Vector3i);
MAKE_PTRARG(Transform2D);
MAKE_PTRARG_BY_REFERENCE(Plane);
@@ -128,9 +130,10 @@ MAKE_PTRARG_BY_REFERENCE(Color);
MAKE_PTRARG(StringName);
MAKE_PTRARG(NodePath);
MAKE_PTRARG(RID);
-MAKE_PTRARG(Dictionary);
+// Object doesn't need this.
MAKE_PTRARG(Callable);
MAKE_PTRARG(Signal);
+MAKE_PTRARG(Dictionary);
MAKE_PTRARG(Array);
MAKE_PTRARG(PackedByteArray);
MAKE_PTRARG(PackedInt32Array);
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index ce7c2bfe14..f61ff29b8f 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index 2f11f22ff8..e0309aa3fe 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 741d05c139..015cee09a7 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -912,11 +912,11 @@ bool Variant::is_zero() const {
} break;
case DICTIONARY: {
- return reinterpret_cast<const Dictionary *>(_data._mem)->empty();
+ return reinterpret_cast<const Dictionary *>(_data._mem)->is_empty();
} break;
case ARRAY: {
- return reinterpret_cast<const Array *>(_data._mem)->empty();
+ return reinterpret_cast<const Array *>(_data._mem)->is_empty();
} break;
@@ -2023,7 +2023,7 @@ Variant::operator Color() const {
if (type == COLOR) {
return *reinterpret_cast<const Color *>(_data._mem);
} else if (type == STRING) {
- return Color::html(operator String());
+ return Color(operator String());
} else if (type == INT) {
return Color::hex(operator int());
} else {
@@ -2338,8 +2338,8 @@ Variant::operator Vector<StringName>() const {
return to;
}
-Variant::operator Margin() const {
- return (Margin) operator int();
+Variant::operator Side() const {
+ return (Side) operator int();
}
Variant::operator Orientation() const {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index d87078b5da..5050aa24ec 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -356,7 +356,7 @@ public:
operator Vector<Vector2>() const;
// some core type enums to convert to
- operator Margin() const;
+ operator Side() const;
operator Orientation() const;
operator IP_Address() const;
@@ -497,6 +497,7 @@ public:
static bool is_builtin_method_const(Variant::Type p_type, const StringName &p_method);
static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method);
static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list);
+ static int get_builtin_method_count(Variant::Type p_type);
void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error);
Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant());
@@ -511,7 +512,7 @@ public:
/* Constructors */
- typedef void (*ValidatedConstructor)(Variant &r_base, const Variant **p_args);
+ typedef void (*ValidatedConstructor)(Variant *r_base, const Variant **p_args);
typedef void (*PTRConstructor)(void *base, const void **p_args);
static int get_constructor_count(Variant::Type p_type);
@@ -535,6 +536,7 @@ public:
static bool has_member(Variant::Type p_type, const StringName &p_member);
static Variant::Type get_member_type(Variant::Type p_type, const StringName &p_member);
static void get_member_list(Type p_type, List<StringName> *r_members);
+ static int get_member_count(Type p_type);
static ValidatedSetter get_member_validated_setter(Variant::Type p_type, const StringName &p_member);
static ValidatedGetter get_member_validated_getter(Variant::Type p_type, const StringName &p_member);
@@ -550,8 +552,8 @@ public:
static bool has_indexing(Variant::Type p_type);
static Variant::Type get_indexed_element_type(Variant::Type p_type);
- typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool &oob);
- typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+ typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool *oob);
+ typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool *oob);
static ValidatedIndexedSetter get_member_validated_indexed_setter(Variant::Type p_type);
static ValidatedIndexedGetter get_member_validated_indexed_getter(Variant::Type p_type);
@@ -571,9 +573,9 @@ public:
static bool is_keyed(Variant::Type p_type);
- typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool &valid);
- typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
- typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool &valid);
+ typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value, bool *valid);
+ typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool *valid);
+ typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key, bool *valid);
static ValidatedKeyedSetter get_member_validated_keyed_setter(Variant::Type p_type);
static ValidatedKeyedGetter get_member_validated_keyed_getter(Variant::Type p_type);
@@ -628,6 +630,7 @@ public:
static bool is_utility_function_vararg(const StringName &p_name);
static void get_utility_function_list(List<StringName> *r_functions);
+ static int get_utility_function_count();
//argsVariant call()
@@ -642,6 +645,7 @@ public:
void static_assign(const Variant &p_variant);
static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants);
+ static int get_constants_count_for_type(Variant::Type p_type);
static bool has_constant(Variant::Type p_type, const StringName &p_value);
static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index d588c83809..54ca1a911d 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -705,6 +705,11 @@ void Variant::get_builtin_method_list(Variant::Type p_type, List<StringName> *p_
}
}
+int Variant::get_builtin_method_count(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
+ return builtin_method_names[p_type].size();
+}
+
Variant::Type Variant::get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
@@ -799,6 +804,13 @@ void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_c
}
}
+int Variant::get_constants_count_for_type(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
+ _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
+
+ return cd.value.size() + cd.variant_value.size();
+}
+
bool Variant::has_constant(Variant::Type p_type, const StringName &p_value) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
_VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type];
@@ -917,7 +929,7 @@ static void _register_variant_builtin_methods() {
bind_method(String, get_extension, sarray(), varray());
bind_method(String, get_basename, sarray(), varray());
bind_method(String, plus_file, sarray("file"), varray());
- bind_method(String, ord_at, sarray("at"), varray());
+ bind_method(String, unicode_at, sarray("at"), varray());
bind_method(String, dedent, sarray(), varray());
// FIXME: String needs to be immutable when binding
//bind_method(String, erase, sarray("position", "chars"), varray());
@@ -928,7 +940,7 @@ static void _register_variant_builtin_methods() {
bind_method(String, md5_buffer, sarray(), varray());
bind_method(String, sha1_buffer, sarray(), varray());
bind_method(String, sha256_buffer, sarray(), varray());
- bind_method(String, empty, sarray(), varray());
+ bind_method(String, is_empty, sarray(), varray());
// FIXME: Static function, not sure how to bind
//bind_method(String, humanize_size, sarray("size"), varray());
@@ -938,13 +950,11 @@ static void _register_variant_builtin_methods() {
bind_method(String, get_file, sarray(), varray());
bind_method(String, xml_escape, sarray("escape_quotes"), varray(false));
bind_method(String, xml_unescape, sarray(), varray());
- bind_method(String, http_escape, sarray(), varray());
- bind_method(String, http_unescape, sarray(), varray());
+ bind_method(String, uri_encode, sarray(), varray());
+ bind_method(String, uri_decode, sarray(), varray());
bind_method(String, c_escape, sarray(), varray());
bind_method(String, c_unescape, sarray(), varray());
bind_method(String, json_escape, sarray(), varray());
- bind_method(String, percent_encode, sarray(), varray());
- bind_method(String, percent_decode, sarray(), varray());
bind_method(String, is_valid_identifier, sarray(), varray());
bind_method(String, is_valid_integer, sarray(), varray());
@@ -956,8 +966,8 @@ static void _register_variant_builtin_methods() {
bind_method(String, to_int, sarray(), varray());
bind_method(String, to_float, sarray(), varray());
- bind_method(String, hex_to_int, sarray("with_prefix"), varray(true));
- bind_method(String, bin_to_int, sarray("with_prefix"), varray(true));
+ bind_method(String, hex_to_int, sarray(), varray());
+ bind_method(String, bin_to_int, sarray(), varray());
bind_method(String, lpad, sarray("min_length", "character"), varray(" "));
bind_method(String, rpad, sarray("min_length", "character"), varray(" "));
@@ -992,7 +1002,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Vector2, move_toward, sarray("to", "delta"), varray());
bind_method(Vector2, rotated, sarray("phi"), varray());
- bind_method(Vector2, tangent, sarray(), varray());
+ bind_method(Vector2, orthogonal, sarray(), varray());
bind_method(Vector2, floor, sarray(), varray());
bind_method(Vector2, ceil, sarray(), varray());
bind_method(Vector2, round, sarray(), varray());
@@ -1004,7 +1014,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, cross, sarray("with"), varray());
bind_method(Vector2, abs, sarray(), varray());
bind_method(Vector2, sign, sarray(), varray());
- bind_method(Vector2, snapped, sarray("by"), varray());
+ bind_method(Vector2, snapped, sarray("step"), varray());
bind_method(Vector2, clamped, sarray("length"), varray());
/* Vector2i */
@@ -1021,11 +1031,11 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
bind_method(Rect2, encloses, sarray("b"), varray());
- bind_method(Rect2, clip, sarray("b"), varray());
+ bind_method(Rect2, intersection, sarray("b"), varray());
bind_method(Rect2, merge, sarray("b"), varray());
bind_method(Rect2, expand, sarray("to"), varray());
- bind_method(Rect2, grow, sarray("by"), varray());
- bind_methodv(Rect2, grow_margin, &Rect2::grow_margin_bind, sarray("margin", "by"), varray());
+ bind_method(Rect2, grow, sarray("amount"), varray());
+ bind_methodv(Rect2, grow_side, &Rect2::grow_side_bind, sarray("side", "amount"), varray());
bind_method(Rect2, grow_individual, sarray("left", "top", "right", "bottom"), varray());
bind_method(Rect2, abs, sarray(), varray());
@@ -1036,11 +1046,11 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2i, has_point, sarray("point"), varray());
bind_method(Rect2i, intersects, sarray("b"), varray());
bind_method(Rect2i, encloses, sarray("b"), varray());
- bind_method(Rect2i, clip, sarray("b"), varray());
+ bind_method(Rect2i, intersection, sarray("b"), varray());
bind_method(Rect2i, merge, sarray("b"), varray());
bind_method(Rect2i, expand, sarray("to"), varray());
- bind_method(Rect2i, grow, sarray("by"), varray());
- bind_methodv(Rect2i, grow_margin, &Rect2i::grow_margin_bind, sarray("margin", "by"), varray());
+ bind_method(Rect2i, grow, sarray("amount"), varray());
+ bind_methodv(Rect2i, grow_side, &Rect2i::grow_side_bind, sarray("side", "amount"), varray());
bind_method(Rect2i, grow_individual, sarray("left", "top", "right", "bottom"), varray());
bind_method(Rect2i, abs, sarray(), varray());
@@ -1049,6 +1059,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, min_axis, sarray(), varray());
bind_method(Vector3, max_axis, sarray(), varray());
bind_method(Vector3, angle_to, sarray("to"), varray());
+ bind_method(Vector3, signed_angle_to, sarray("to", "axis"), varray());
bind_method(Vector3, direction_to, sarray("b"), varray());
bind_method(Vector3, distance_to, sarray("b"), varray());
bind_method(Vector3, distance_squared_to, sarray("b"), varray());
@@ -1058,7 +1069,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, is_normalized, sarray(), varray());
bind_method(Vector3, is_equal_approx, sarray("to"), varray());
bind_method(Vector3, inverse, sarray(), varray());
- bind_method(Vector3, snapped, sarray("by"), varray());
+ bind_method(Vector3, snapped, sarray("step"), varray());
bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray());
bind_method(Vector3, lerp, sarray("to", "weight"), varray());
bind_method(Vector3, slerp, sarray("to", "weight"), varray());
@@ -1114,10 +1125,6 @@ static void _register_variant_builtin_methods() {
bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Quat, get_euler, sarray(), varray());
- // FIXME: Quat is atomic, this should be done via construcror
- //ADDFUNC1(QUAT, NIL, Quat, set_euler, VECTOR3, "euler", varray());
- //ADDFUNC2(QUAT, NIL, Quat, set_axis_angle, VECTOR3, "axis", FLOAT, "angle", varray());
-
/* Color */
bind_method(Color, to_argb32, sarray(), varray());
@@ -1204,7 +1211,7 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, transposed, sarray(), varray());
bind_method(Basis, orthonormalized, sarray(), varray());
bind_method(Basis, determinant, sarray(), varray());
- bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, float) const>(&Basis::rotated), sarray("axis", "phi"), varray());
+ bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "phi"), varray());
bind_method(Basis, scaled, sarray("scale"), varray());
bind_method(Basis, get_scale, sarray(), varray());
bind_method(Basis, get_euler, sarray(), varray());
@@ -1250,14 +1257,14 @@ static void _register_variant_builtin_methods() {
bind_method(Transform, rotated, sarray("axis", "phi"), varray());
bind_method(Transform, scaled, sarray("scale"), varray());
bind_method(Transform, translated, sarray("offset"), varray());
- bind_method(Transform, looking_at, sarray("target", "up"), varray());
+ bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform, is_equal_approx, sarray("xform"), varray());
/* Dictionary */
bind_method(Dictionary, size, sarray(), varray());
- bind_method(Dictionary, empty, sarray(), varray());
+ bind_method(Dictionary, is_empty, sarray(), varray());
bind_method(Dictionary, clear, sarray(), varray());
bind_method(Dictionary, has, sarray("key"), varray());
bind_method(Dictionary, has_all, sarray("keys"), varray());
@@ -1271,7 +1278,7 @@ static void _register_variant_builtin_methods() {
/* Array */
bind_method(Array, size, sarray(), varray());
- bind_method(Array, empty, sarray(), varray());
+ bind_method(Array, is_empty, sarray(), varray());
bind_method(Array, clear, sarray(), varray());
bind_method(Array, hash, sarray(), varray());
bind_method(Array, push_back, sarray("value"), varray());
@@ -1292,10 +1299,10 @@ static void _register_variant_builtin_methods() {
bind_method(Array, pop_back, sarray(), varray());
bind_method(Array, pop_front, sarray(), varray());
bind_method(Array, sort, sarray(), varray());
- bind_method(Array, sort_custom, sarray("obj", "func"), varray());
+ bind_method(Array, sort_custom, sarray("func"), varray());
bind_method(Array, shuffle, sarray(), varray());
bind_method(Array, bsearch, sarray("value", "before"), varray(true));
- bind_method(Array, bsearch_custom, sarray("value", "obj", "func", "before"), varray(true));
+ bind_method(Array, bsearch_custom, sarray("value", "func", "before"), varray(true));
bind_method(Array, invert, sarray(), varray());
bind_method(Array, duplicate, sarray("deep"), varray(false));
bind_method(Array, slice, sarray("begin", "end", "step", "deep"), varray(1, false));
@@ -1304,7 +1311,7 @@ static void _register_variant_builtin_methods() {
/* Byte Array */
bind_method(PackedByteArray, size, sarray(), varray());
- bind_method(PackedByteArray, empty, sarray(), varray());
+ bind_method(PackedByteArray, is_empty, sarray(), varray());
bind_method(PackedByteArray, set, sarray("index", "value"), varray());
bind_method(PackedByteArray, push_back, sarray("value"), varray());
bind_method(PackedByteArray, append, sarray("value"), varray());
@@ -1316,6 +1323,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, invert, sarray(), varray());
bind_method(PackedByteArray, subarray, sarray("from", "to"), varray());
bind_method(PackedByteArray, sort, sarray(), varray());
+ bind_method(PackedByteArray, duplicate, sarray(), varray());
bind_function(PackedByteArray, get_string_from_ascii, _VariantCall::func_PackedByteArray_get_string_from_ascii, sarray(), varray());
bind_function(PackedByteArray, get_string_from_utf8, _VariantCall::func_PackedByteArray_get_string_from_utf8, sarray(), varray());
@@ -1329,7 +1337,7 @@ static void _register_variant_builtin_methods() {
/* Int32 Array */
bind_method(PackedInt32Array, size, sarray(), varray());
- bind_method(PackedInt32Array, empty, sarray(), varray());
+ bind_method(PackedInt32Array, is_empty, sarray(), varray());
bind_method(PackedInt32Array, set, sarray("index", "value"), varray());
bind_method(PackedInt32Array, push_back, sarray("value"), varray());
bind_method(PackedInt32Array, append, sarray("value"), varray());
@@ -1342,11 +1350,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, subarray, sarray("from", "to"), varray());
bind_method(PackedInt32Array, to_byte_array, sarray(), varray());
bind_method(PackedInt32Array, sort, sarray(), varray());
+ bind_method(PackedInt32Array, duplicate, sarray(), varray());
/* Int64 Array */
bind_method(PackedInt64Array, size, sarray(), varray());
- bind_method(PackedInt64Array, empty, sarray(), varray());
+ bind_method(PackedInt64Array, is_empty, sarray(), varray());
bind_method(PackedInt64Array, set, sarray("index", "value"), varray());
bind_method(PackedInt64Array, push_back, sarray("value"), varray());
bind_method(PackedInt64Array, append, sarray("value"), varray());
@@ -1359,11 +1368,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, subarray, sarray("from", "to"), varray());
bind_method(PackedInt64Array, to_byte_array, sarray(), varray());
bind_method(PackedInt64Array, sort, sarray(), varray());
+ bind_method(PackedInt64Array, duplicate, sarray(), varray());
/* Float32 Array */
bind_method(PackedFloat32Array, size, sarray(), varray());
- bind_method(PackedFloat32Array, empty, sarray(), varray());
+ bind_method(PackedFloat32Array, is_empty, sarray(), varray());
bind_method(PackedFloat32Array, set, sarray("index", "value"), varray());
bind_method(PackedFloat32Array, push_back, sarray("value"), varray());
bind_method(PackedFloat32Array, append, sarray("value"), varray());
@@ -1376,11 +1386,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, subarray, sarray("from", "to"), varray());
bind_method(PackedFloat32Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat32Array, sort, sarray(), varray());
+ bind_method(PackedFloat32Array, duplicate, sarray(), varray());
/* Float64 Array */
bind_method(PackedFloat64Array, size, sarray(), varray());
- bind_method(PackedFloat64Array, empty, sarray(), varray());
+ bind_method(PackedFloat64Array, is_empty, sarray(), varray());
bind_method(PackedFloat64Array, set, sarray("index", "value"), varray());
bind_method(PackedFloat64Array, push_back, sarray("value"), varray());
bind_method(PackedFloat64Array, append, sarray("value"), varray());
@@ -1393,11 +1404,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, subarray, sarray("from", "to"), varray());
bind_method(PackedFloat64Array, to_byte_array, sarray(), varray());
bind_method(PackedFloat64Array, sort, sarray(), varray());
+ bind_method(PackedFloat64Array, duplicate, sarray(), varray());
/* String Array */
bind_method(PackedStringArray, size, sarray(), varray());
- bind_method(PackedStringArray, empty, sarray(), varray());
+ bind_method(PackedStringArray, is_empty, sarray(), varray());
bind_method(PackedStringArray, set, sarray("index", "value"), varray());
bind_method(PackedStringArray, push_back, sarray("value"), varray());
bind_method(PackedStringArray, append, sarray("value"), varray());
@@ -1410,11 +1422,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, subarray, sarray("from", "to"), varray());
bind_method(PackedStringArray, to_byte_array, sarray(), varray());
bind_method(PackedStringArray, sort, sarray(), varray());
+ bind_method(PackedStringArray, duplicate, sarray(), varray());
/* Vector2 Array */
bind_method(PackedVector2Array, size, sarray(), varray());
- bind_method(PackedVector2Array, empty, sarray(), varray());
+ bind_method(PackedVector2Array, is_empty, sarray(), varray());
bind_method(PackedVector2Array, set, sarray("index", "value"), varray());
bind_method(PackedVector2Array, push_back, sarray("value"), varray());
bind_method(PackedVector2Array, append, sarray("value"), varray());
@@ -1427,11 +1440,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, subarray, sarray("from", "to"), varray());
bind_method(PackedVector2Array, to_byte_array, sarray(), varray());
bind_method(PackedVector2Array, sort, sarray(), varray());
+ bind_method(PackedVector2Array, duplicate, sarray(), varray());
/* Vector3 Array */
bind_method(PackedVector3Array, size, sarray(), varray());
- bind_method(PackedVector3Array, empty, sarray(), varray());
+ bind_method(PackedVector3Array, is_empty, sarray(), varray());
bind_method(PackedVector3Array, set, sarray("index", "value"), varray());
bind_method(PackedVector3Array, push_back, sarray("value"), varray());
bind_method(PackedVector3Array, append, sarray("value"), varray());
@@ -1444,11 +1458,12 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, subarray, sarray("from", "to"), varray());
bind_method(PackedVector3Array, to_byte_array, sarray(), varray());
bind_method(PackedVector3Array, sort, sarray(), varray());
+ bind_method(PackedVector3Array, duplicate, sarray(), varray());
/* Color Array */
bind_method(PackedColorArray, size, sarray(), varray());
- bind_method(PackedColorArray, empty, sarray(), varray());
+ bind_method(PackedColorArray, is_empty, sarray(), varray());
bind_method(PackedColorArray, set, sarray("index", "value"), varray());
bind_method(PackedColorArray, push_back, sarray("value"), varray());
bind_method(PackedColorArray, append, sarray("value"), varray());
@@ -1461,6 +1476,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, subarray, sarray("from", "to"), varray());
bind_method(PackedColorArray, to_byte_array, sarray(), varray());
bind_method(PackedColorArray, sort, sarray(), varray());
+ bind_method(PackedColorArray, duplicate, sarray(), varray());
/* Register constants */
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3bb3fa3634..f0c9e52b46 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -39,6 +39,60 @@
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
+template <class T>
+struct PtrConstruct {};
+
+#define MAKE_PTRCONSTRUCT(m_type) \
+ template <> \
+ struct PtrConstruct<m_type> { \
+ _FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \
+ memnew_placement(p_ptr, m_type(p_value)); \
+ } \
+ };
+
+MAKE_PTRCONSTRUCT(bool);
+MAKE_PTRCONSTRUCT(int64_t);
+MAKE_PTRCONSTRUCT(double);
+MAKE_PTRCONSTRUCT(String);
+MAKE_PTRCONSTRUCT(Vector2);
+MAKE_PTRCONSTRUCT(Vector2i);
+MAKE_PTRCONSTRUCT(Rect2);
+MAKE_PTRCONSTRUCT(Rect2i);
+MAKE_PTRCONSTRUCT(Vector3);
+MAKE_PTRCONSTRUCT(Vector3i);
+MAKE_PTRCONSTRUCT(Transform2D);
+MAKE_PTRCONSTRUCT(Plane);
+MAKE_PTRCONSTRUCT(Quat);
+MAKE_PTRCONSTRUCT(AABB);
+MAKE_PTRCONSTRUCT(Basis);
+MAKE_PTRCONSTRUCT(Transform);
+MAKE_PTRCONSTRUCT(Color);
+MAKE_PTRCONSTRUCT(StringName);
+MAKE_PTRCONSTRUCT(NodePath);
+MAKE_PTRCONSTRUCT(RID);
+
+template <>
+struct PtrConstruct<Object *> {
+ _FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) {
+ *((Object **)p_ptr) = p_value;
+ }
+};
+
+MAKE_PTRCONSTRUCT(Callable);
+MAKE_PTRCONSTRUCT(Signal);
+MAKE_PTRCONSTRUCT(Dictionary);
+MAKE_PTRCONSTRUCT(Array);
+MAKE_PTRCONSTRUCT(PackedByteArray);
+MAKE_PTRCONSTRUCT(PackedInt32Array);
+MAKE_PTRCONSTRUCT(PackedInt64Array);
+MAKE_PTRCONSTRUCT(PackedFloat32Array);
+MAKE_PTRCONSTRUCT(PackedFloat64Array);
+MAKE_PTRCONSTRUCT(PackedStringArray);
+MAKE_PTRCONSTRUCT(PackedVector2Array);
+MAKE_PTRCONSTRUCT(PackedVector3Array);
+MAKE_PTRCONSTRUCT(PackedColorArray);
+MAKE_PTRCONSTRUCT(Variant);
+
template <class T, class... P>
class VariantConstructor {
template <size_t... Is>
@@ -59,7 +113,7 @@ class VariantConstructor {
template <size_t... Is>
static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) {
- PtrToArg<T>::encode(T(PtrToArg<P>::convert(p_args[Is])...), base);
+ PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base);
}
public:
@@ -69,9 +123,9 @@ public:
construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{});
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<T>::change(&r_ret);
- validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, BuildIndexSequence<sizeof...(P)>{});
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(r_ret);
+ validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{});
}
static void ptr_construct(void *base, const void **p_args) {
ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{});
@@ -107,12 +161,12 @@ public:
}
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign(&r_ret, p_args[0]);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
+ VariantInternal::object_assign(r_ret, p_args[0]);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Object *>::encode(PtrToArg<Object *>::convert(p_args[0]), base);
+ PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base);
}
static int get_argument_count() {
@@ -141,12 +195,12 @@ public:
VariantInternal::object_assign_null(&r_ret);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
+ VariantInternal::object_assign_null(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Object *>::encode(nullptr, base);
+ PtrConstruct<Object *>::construct(nullptr, base);
}
static int get_argument_count() {
@@ -194,12 +248,12 @@ public:
*VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<Callable>::change(&r_ret);
- *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<Callable>::change(r_ret);
+ *VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Callable>::encode(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
+ PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
}
static int get_argument_count() {
@@ -251,12 +305,12 @@ public:
*VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<Signal>::change(&r_ret);
- *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<Signal>::change(r_ret);
+ *VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]));
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Signal>::encode(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
+ PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base);
}
static int get_argument_count() {
@@ -298,9 +352,9 @@ public:
}
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<Array>::change(&r_ret);
- Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<Array>::change(r_ret);
+ Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret);
const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]);
int size = src_arr.size();
@@ -319,7 +373,7 @@ public:
dst_arr[i] = src_arr[i];
}
- PtrToArg<Array>::encode(dst_arr, base);
+ PtrConstruct<Array>::construct(dst_arr, base);
}
static int get_argument_count() {
@@ -357,10 +411,10 @@ public:
}
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<T>::change(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change(r_ret);
const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
- T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret);
+ T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret);
int size = src_arr.size();
dst_arr.resize(size);
@@ -378,7 +432,7 @@ public:
dst_arr.write[i] = src_arr[i];
}
- PtrToArg<T>::encode(dst_arr, base);
+ PtrConstruct<T>::construct(dst_arr, base);
}
static int get_argument_count() {
@@ -408,11 +462,11 @@ public:
VariantInternal::clear(&r_ret);
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Variant>::encode(Variant(), base);
+ PtrConstruct<Variant>::construct(Variant(), base);
}
static int get_argument_count() {
@@ -436,11 +490,11 @@ public:
r_error.error = Callable::CallError::CALL_OK;
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantTypeChanger<T>::change_and_reset(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantTypeChanger<T>::change_and_reset(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<T>::encode(T(), base);
+ PtrConstruct<T>::construct(T(), base);
}
static int get_argument_count() {
@@ -463,8 +517,8 @@ public:
r_error.error = Callable::CallError::CALL_OK;
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
ERR_FAIL_MSG("can't ptrcall nil constructor");
@@ -491,12 +545,12 @@ public:
r_error.error = Callable::CallError::CALL_OK;
}
- static void validated_construct(Variant &r_ret, const Variant **p_args) {
- VariantInternal::clear(&r_ret);
- VariantInternal::object_assign_null(&r_ret);
+ static void validated_construct(Variant *r_ret, const Variant **p_args) {
+ VariantInternal::clear(r_ret);
+ VariantInternal::object_assign_null(r_ret);
}
static void ptr_construct(void *base, const void **p_args) {
- PtrToArg<Object *>::encode(nullptr, base);
+ PtrConstruct<Object *>::construct(nullptr, base);
}
static int get_argument_count() {
@@ -634,6 +688,8 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructor<Color, Color, double>>(sarray("from", "alpha"));
add_constructor<VariantConstructor<Color, double, double, double>>(sarray("r", "g", "b"));
add_constructor<VariantConstructor<Color, double, double, double, double>>(sarray("r", "g", "b", "a"));
+ add_constructor<VariantConstructor<Color, String>>(sarray("code"));
+ add_constructor<VariantConstructor<Color, String, double>>(sarray("code", "alpha"));
add_constructor<VariantConstructNoArgs<StringName>>(sarray());
add_constructor<VariantConstructor<StringName, StringName>>(sarray("from"));
@@ -717,6 +773,7 @@ void Variant::_unregister_variant_constructors() {
}
void Variant::construct(Variant::Type p_type, Variant &base, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX);
uint32_t s = construct_data[p_type].size();
for (uint32_t i = 0; i < s; i++) {
int argc = construct_data[p_type][i].argument_count;
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 804abf8fbc..7d33d85cd6 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -743,7 +743,7 @@ VARIANT_ACCESSOR_NUMBER(int64_t)
VARIANT_ACCESSOR_NUMBER(uint64_t)
VARIANT_ACCESSOR_NUMBER(char32_t)
VARIANT_ACCESSOR_NUMBER(Error)
-VARIANT_ACCESSOR_NUMBER(Margin)
+VARIANT_ACCESSOR_NUMBER(Side)
template <>
struct VariantInternalAccessor<ObjectID> {
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index df29ec7b63..e0a3cf4215 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -318,6 +318,7 @@ public:
r_valid = true;
}
static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
+ VariantTypeChanger<R>::change(r_ret);
*VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right);
}
static void ptr_evaluate(const void *left, const void *right, void *r_ret) {
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 5a0bbf041b..ed936c626b 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -743,6 +743,8 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
return ERR_PARSE_ERROR;
}
+ REF ref = REF(Object::cast_to<Reference>(obj));
+
get_token(p_stream, token, line, r_err_str);
if (token.type != TK_COMMA) {
r_err_str = "Expected ',' after object type";
@@ -767,12 +769,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
}
if (token2.type == TK_PARENTHESIS_CLOSE) {
- Reference *reference = Object::cast_to<Reference>(obj);
- if (reference) {
- value = REF(reference);
- } else {
- value = obj;
- }
+ value = ref.is_valid() ? Variant(ref) : Variant(obj);
return OK;
}
diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h
index cf1941a40e..5703f0200c 100644
--- a/core/variant/variant_parser.h
+++ b/core/variant/variant_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index f6a2c11830..ea8263402a 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -437,6 +437,11 @@ void Variant::get_member_list(Variant::Type p_type, List<StringName> *r_members)
}
}
+int Variant::get_member_count(Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1);
+ return variant_setters_getters_names[p_type].size();
+}
+
Variant::ValidatedSetter Variant::get_member_validated_setter(Variant::Type p_type, const StringName &p_member) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
@@ -582,18 +587,18 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_TYPED(m_base_type, m_elem_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -603,10 +608,10 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, v.size()); \
PtrToArg<m_elem_type>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
return; \
} \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
@@ -614,25 +619,25 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -648,18 +653,18 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_TYPED_NUMERIC(m_base_type, m_elem_type, m_assign_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -669,14 +674,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, v.size()); \
PtrToArg<m_elem_type>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
m_assign_type num; \
@@ -685,25 +690,25 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
} else if (value->get_type() == Variant::FLOAT) { \
num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
} else { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = num; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)).write[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -719,14 +724,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(m_base_type, m_elem_type, m_assign_type, m_max) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -734,10 +739,10 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, m_max); \
PtrToArg<m_elem_type>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
m_assign_type num; \
@@ -746,21 +751,21 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
} else if (value->get_type() == Variant::FLOAT) { \
num = (m_assign_type)*VariantGetInternalPtr<double>::get_ptr(value); \
} else { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = num; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -774,14 +779,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(m_base_type, m_elem_type, m_accessor, m_max) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))m_accessor[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -789,27 +794,27 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, m_max); \
PtrToArg<m_elem_type>::encode(v m_accessor[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
} \
if (index < 0 || index >= m_max) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base)) m_accessor[index] = *VariantGetInternalPtr<m_elem_type>::get_ptr(value); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -823,14 +828,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_BULTIN_FUNC(m_base_type, m_elem_type, m_set, m_get, m_max) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantTypeAdjust<m_elem_type>::adjust(value); \
*VariantGetInternalPtr<m_elem_type>::get_ptr(value) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_get(index); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -838,27 +843,27 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, m_max); \
PtrToArg<m_elem_type>::encode(v.m_get(index), member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
if (value->get_type() != GetTypeInfo<m_elem_type>::VARIANT_TYPE) { \
- oob = false; \
- valid = false; \
+ *oob = false; \
+ *valid = false; \
} \
if (index < 0 || index >= m_max) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
if (index < 0 || index >= m_max) { \
- oob = true; \
+ *oob = true; \
return; \
} \
VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_set(index, *VariantGetInternalPtr<m_elem_type>::get_ptr(value)); \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -872,17 +877,17 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_VARIANT(m_base_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
*value = (*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index]; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -892,31 +897,31 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
OOB_TEST(index, v.size()); \
PtrToArg<Variant>::encode(v[index], member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
- valid = false; \
+ *oob = true; \
+ *valid = false; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
int64_t size = VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); \
if (index < 0) { \
index += size; \
} \
if (index < 0 || index >= size) { \
- oob = true; \
+ *oob = true; \
return; \
} \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -932,14 +937,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#define INDEXED_SETGET_STRUCT_DICT(m_base_type) \
struct VariantIndexedSetGet_##m_base_type { \
- static void get(const Variant *base, int64_t index, Variant *value, bool &oob) { \
+ static void get(const Variant *base, int64_t index, Variant *value, bool *oob) { \
const Variant *ptr = VariantGetInternalPtr<m_base_type>::get_ptr(base)->getptr(index); \
if (!ptr) { \
- oob = true; \
+ *oob = true; \
return; \
} \
*value = *ptr; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_get(const void *base, int64_t index, void *member) { \
/* avoid ptrconvert for performance*/ \
@@ -948,14 +953,14 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
NULL_TEST(ptr); \
PtrToArg<Variant>::encode(*ptr, member); \
} \
- static void set(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob) { \
+ static void set(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob) { \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
- valid = true; \
+ *oob = false; \
+ *valid = true; \
} \
- static void validated_set(Variant *base, int64_t index, const Variant *value, bool &oob) { \
+ static void validated_set(Variant *base, int64_t index, const Variant *value, bool *oob) { \
(*VariantGetInternalPtr<m_base_type>::get_ptr(base))[index] = *value; \
- oob = false; \
+ *oob = false; \
} \
static void ptr_set(void *base, int64_t index, const void *member) { \
m_base_type &v = *reinterpret_cast<m_base_type *>(base); \
@@ -989,8 +994,8 @@ INDEXED_SETGET_STRUCT_VARIANT(Array)
INDEXED_SETGET_STRUCT_DICT(Dictionary)
struct VariantIndexedSetterGetterInfo {
- void (*setter)(Variant *base, int64_t index, const Variant *value, bool &valid, bool &oob);
- void (*getter)(const Variant *base, int64_t index, Variant *value, bool &oob);
+ void (*setter)(Variant *base, int64_t index, const Variant *value, bool *valid, bool *oob);
+ void (*getter)(const Variant *base, int64_t index, Variant *value, bool *oob);
Variant::ValidatedIndexedSetter validated_setter;
Variant::ValidatedIndexedGetter validated_getter;
@@ -1083,7 +1088,7 @@ Variant::PTRIndexedGetter Variant::get_member_ptr_indexed_getter(Variant::Type p
void Variant::set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid, bool &r_oob) {
if (likely(variant_indexed_setters_getters[type].valid)) {
- variant_indexed_setters_getters[type].setter(this, p_index, &p_value, r_valid, r_oob);
+ variant_indexed_setters_getters[type].setter(this, p_index, &p_value, &r_valid, &r_oob);
} else {
r_valid = false;
r_oob = false;
@@ -1092,7 +1097,7 @@ void Variant::set_indexed(int64_t p_index, const Variant &p_value, bool &r_valid
Variant Variant::get_indexed(int64_t p_index, bool &r_valid, bool &r_oob) const {
if (likely(variant_indexed_setters_getters[type].valid)) {
Variant ret;
- variant_indexed_setters_getters[type].getter(this, p_index, &ret, r_oob);
+ variant_indexed_setters_getters[type].getter(this, p_index, &ret, &r_oob);
r_valid = !r_oob;
return ret;
} else {
@@ -1111,14 +1116,14 @@ uint64_t Variant::get_indexed_size() const {
}
struct VariantKeyedSetGetDictionary {
- static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool *r_valid) {
const Variant *ptr = VariantGetInternalPtr<Dictionary>::get_ptr(base)->getptr(*key);
if (!ptr) {
- r_valid = false;
+ *r_valid = false;
return;
}
*value = *ptr;
- r_valid = true;
+ *r_valid = true;
}
static void ptr_get(const void *base, const void *key, void *value) {
/* avoid ptrconvert for performance*/
@@ -1127,17 +1132,17 @@ struct VariantKeyedSetGetDictionary {
NULL_TEST(ptr);
PtrToArg<Variant>::encode(*ptr, value);
}
- static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ static void set(Variant *base, const Variant *key, const Variant *value, bool *r_valid) {
(*VariantGetInternalPtr<Dictionary>::get_ptr(base))[*key] = *value;
- r_valid = true;
+ *r_valid = true;
}
static void ptr_set(void *base, const void *key, const void *value) {
Dictionary &v = *reinterpret_cast<Dictionary *>(base);
v[PtrToArg<Variant>::convert(key)] = PtrToArg<Variant>::convert(value);
}
- static bool has(const Variant *base, const Variant *key, bool &r_valid) {
- r_valid = true;
+ static bool has(const Variant *base, const Variant *key, bool *r_valid) {
+ *r_valid = true;
return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key);
}
static bool ptr_has(const void *base, const void *key) {
@@ -1148,15 +1153,15 @@ struct VariantKeyedSetGetDictionary {
};
struct VariantKeyedSetGetObject {
- static void get(const Variant *base, const Variant *key, Variant *value, bool &r_valid) {
+ static void get(const Variant *base, const Variant *key, Variant *value, bool *r_valid) {
Object *obj = base->get_validated_object();
if (!obj) {
- r_valid = false;
+ *r_valid = false;
*value = Variant();
return;
}
- *value = obj->getvar(*key, &r_valid);
+ *value = obj->getvar(*key, r_valid);
}
static void ptr_get(const void *base, const void *key, void *value) {
const Object *obj = PtrToArg<Object *>::convert(base);
@@ -1164,14 +1169,14 @@ struct VariantKeyedSetGetObject {
Variant v = obj->getvar(PtrToArg<Variant>::convert(key));
PtrToArg<Variant>::encode(v, value);
}
- static void set(Variant *base, const Variant *key, const Variant *value, bool &r_valid) {
+ static void set(Variant *base, const Variant *key, const Variant *value, bool *r_valid) {
Object *obj = base->get_validated_object();
if (!obj) {
- r_valid = false;
+ *r_valid = false;
return;
}
- obj->setvar(*key, *value, &r_valid);
+ obj->setvar(*key, *value, r_valid);
}
static void ptr_set(void *base, const void *key, const void *value) {
Object *obj = PtrToArg<Object *>::convert(base);
@@ -1179,13 +1184,13 @@ struct VariantKeyedSetGetObject {
obj->setvar(PtrToArg<Variant>::convert(key), PtrToArg<Variant>::convert(value));
}
- static bool has(const Variant *base, const Variant *key, bool &r_valid) {
+ static bool has(const Variant *base, const Variant *key, bool *r_valid) {
Object *obj = base->get_validated_object();
- if (obj != nullptr) {
- r_valid = false;
+ if (!obj) {
+ *r_valid = false;
return false;
}
- r_valid = true;
+ *r_valid = true;
bool exists;
obj->getvar(*key, &exists);
return exists;
@@ -1199,14 +1204,6 @@ struct VariantKeyedSetGetObject {
}
};
-/*typedef void (*ValidatedKeyedSetter)(Variant *base, const Variant *key, const Variant *value);
-typedef void (*ValidatedKeyedGetter)(const Variant *base, const Variant *key, Variant *value, bool &valid);
-typedef bool (*ValidatedKeyedChecker)(const Variant *base, const Variant *key);
-
-typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value);
-typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value);
-typedef bool (*PTRKeyedChecker)(const void *base, const void *key);*/
-
struct VariantKeyedSetterGetterInfo {
Variant::ValidatedKeyedSetter validated_setter;
Variant::ValidatedKeyedGetter validated_getter;
@@ -1274,7 +1271,7 @@ Variant::PTRKeyedChecker Variant::get_member_ptr_keyed_checker(Variant::Type p_t
void Variant::set_keyed(const Variant &p_key, const Variant &p_value, bool &r_valid) {
if (likely(variant_keyed_setters_getters[type].valid)) {
- variant_keyed_setters_getters[type].validated_setter(this, &p_key, &p_value, r_valid);
+ variant_keyed_setters_getters[type].validated_setter(this, &p_key, &p_value, &r_valid);
} else {
r_valid = false;
}
@@ -1282,7 +1279,7 @@ void Variant::set_keyed(const Variant &p_key, const Variant &p_value, bool &r_va
Variant Variant::get_keyed(const Variant &p_key, bool &r_valid) const {
if (likely(variant_keyed_setters_getters[type].valid)) {
Variant ret;
- variant_keyed_setters_getters[type].validated_getter(this, &p_key, &ret, r_valid);
+ variant_keyed_setters_getters[type].validated_getter(this, &p_key, &ret, &r_valid);
return ret;
} else {
r_valid = false;
@@ -1291,7 +1288,7 @@ Variant Variant::get_keyed(const Variant &p_key, bool &r_valid) const {
}
bool Variant::has_key(const Variant &p_key, bool &r_valid) const {
if (likely(variant_keyed_setters_getters[type].valid)) {
- return variant_keyed_setters_getters[type].validated_checker(this, &p_key, r_valid);
+ return variant_keyed_setters_getters[type].validated_checker(this, &p_key, &r_valid);
} else {
r_valid = false;
return false;
@@ -1480,7 +1477,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
case STRING: {
const String *str = reinterpret_cast<const String *>(_data._mem);
- if (str->empty()) {
+ if (str->is_empty()) {
return false;
}
r_iter = 0;
@@ -1488,7 +1485,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
} break;
case DICTIONARY: {
const Dictionary *dic = reinterpret_cast<const Dictionary *>(_data._mem);
- if (dic->empty()) {
+ if (dic->is_empty()) {
return false;
}
@@ -1499,7 +1496,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
} break;
case ARRAY: {
const Array *arr = reinterpret_cast<const Array *>(_data._mem);
- if (arr->empty()) {
+ if (arr->is_empty()) {
return false;
}
r_iter = 0;
@@ -2031,6 +2028,24 @@ Variant Variant::duplicate(bool deep) const {
return operator Dictionary().duplicate(deep);
case ARRAY:
return operator Array().duplicate(deep);
+ case PACKED_BYTE_ARRAY:
+ return operator Vector<uint8_t>().duplicate();
+ case PACKED_INT32_ARRAY:
+ return operator Vector<int32_t>().duplicate();
+ case PACKED_INT64_ARRAY:
+ return operator Vector<int64_t>().duplicate();
+ case PACKED_FLOAT32_ARRAY:
+ return operator Vector<float>().duplicate();
+ case PACKED_FLOAT64_ARRAY:
+ return operator Vector<double>().duplicate();
+ case PACKED_STRING_ARRAY:
+ return operator Vector<String>().duplicate();
+ case PACKED_VECTOR2_ARRAY:
+ return operator Vector<Vector2>().duplicate();
+ case PACKED_VECTOR3_ARRAY:
+ return operator Vector<Vector3>().duplicate();
+ case PACKED_COLOR_ARRAY:
+ return operator Vector<Color>().duplicate();
default:
return *this;
}
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index d54e223a99..f154ab1ed6 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */
@@ -217,8 +217,8 @@ struct VariantUtilityFunctions {
return Math::range_step_decimals(step);
}
- static inline double stepify(double value, double step) {
- return Math::stepify(value, step);
+ static inline double snapped(double value, double step) {
+ return Math::snapped(value, step);
}
static inline double lerp(double from, double to, double weight) {
@@ -291,7 +291,7 @@ struct VariantUtilityFunctions {
Variant ret;
for (int i = 1; i < p_argcount; i++) {
bool valid;
- Variant::evaluate(Variant::OP_GREATER, base, *p_args[i], ret, valid);
+ Variant::evaluate(Variant::OP_LESS, base, *p_args[i], ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.expected = base.get_type();
@@ -324,7 +324,7 @@ struct VariantUtilityFunctions {
Variant ret;
for (int i = 1; i < p_argcount; i++) {
bool valid;
- Variant::evaluate(Variant::OP_LESS, base, *p_args[i], ret, valid);
+ Variant::evaluate(Variant::OP_GREATER, base, *p_args[i], ret, valid);
if (!valid) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.expected = base.get_type();
@@ -1181,7 +1181,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(range_step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(stepify, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1379,3 +1379,7 @@ void Variant::get_utility_function_list(List<StringName> *r_functions) {
r_functions->push_back(E->get());
}
}
+
+int Variant::get_utility_function_count() {
+ return utility_function_name_table.size();
+}
diff --git a/core/version.h b/core/version.h
index 1198f62db4..2a4fa9cfd4 100644
--- a/core/version.h
+++ b/core/version.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* 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 */