summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/SCsub2
-rw-r--r--core/config/engine.cpp17
-rw-r--r--core/config/engine.h10
-rw-r--r--core/config/project_settings.cpp108
-rw-r--r--core/core_bind.cpp691
-rw-r--r--core/core_bind.h177
-rw-r--r--core/core_builders.py6
-rw-r--r--core/core_constants.cpp10
-rw-r--r--core/debugger/remote_debugger.cpp87
-rw-r--r--core/debugger/remote_debugger.h2
-rw-r--r--core/debugger/remote_debugger_peer.cpp8
-rw-r--r--core/debugger/remote_debugger_peer.h8
-rw-r--r--core/doc_data.h341
-rw-r--r--core/error/error_macros.h67
-rw-r--r--core/extension/SCsub7
-rw-r--r--core/extension/extension_api_dump.cpp57
-rw-r--r--core/extension/gdnative_interface.cpp75
-rw-r--r--core/extension/gdnative_interface.h89
-rw-r--r--core/extension/make_interface_dumper.py47
-rw-r--r--core/extension/make_wrappers.py83
-rw-r--r--core/extension/native_extension.cpp111
-rw-r--r--core/extension/native_extension.h16
-rw-r--r--core/input/gamecontrollerdb.txt20
-rw-r--r--core/input/godotcontrollerdb.txt1
-rw-r--r--core/input/input.cpp5
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/input/input_event.cpp61
-rw-r--r--core/input/input_event.h4
-rw-r--r--core/input/input_map.cpp36
-rw-r--r--core/io/dir_access.cpp164
-rw-r--r--core/io/dir_access.h33
-rw-r--r--core/io/file_access.cpp208
-rw-r--r--core/io/file_access.h50
-rw-r--r--core/io/file_access_compressed.cpp2
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp10
-rw-r--r--core/io/file_access_encrypted.h2
-rw-r--r--core/io/file_access_memory.cpp2
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp10
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/file_access_zip.cpp4
-rw-r--r--core/io/file_access_zip.h2
-rw-r--r--core/io/http_client_tcp.cpp20
-rw-r--r--core/io/image.cpp108
-rw-r--r--core/io/image.h20
-rw-r--r--core/io/image_loader.cpp52
-rw-r--r--core/io/image_loader.h51
-rw-r--r--core/io/json.cpp23
-rw-r--r--core/io/json.h6
-rw-r--r--core/io/logger.cpp2
-rw-r--r--core/io/marshalls.cpp6
-rw-r--r--core/io/resource.cpp2
-rw-r--r--core/io/resource_format_binary.cpp103
-rw-r--r--core/io/resource_importer.cpp4
-rw-r--r--core/io/resource_loader.cpp49
-rw-r--r--core/io/resource_loader.h1
-rw-r--r--core/io/resource_saver.cpp51
-rw-r--r--core/io/resource_saver.h2
-rw-r--r--core/io/resource_uid.cpp7
-rw-r--r--core/io/stream_peer_gzip.cpp209
-rw-r--r--core/io/stream_peer_gzip.h76
-rw-r--r--core/io/stream_peer_tcp.cpp4
-rw-r--r--core/io/stream_peer_tcp.h2
-rw-r--r--core/io/xml_parser.cpp69
-rw-r--r--core/io/xml_parser.h8
-rw-r--r--core/io/zip_io.cpp12
-rw-r--r--core/math/a_star_grid_2d.cpp24
-rw-r--r--core/math/a_star_grid_2d.h2
-rw-r--r--core/math/aabb.cpp7
-rw-r--r--core/math/aabb.h4
-rw-r--r--core/math/audio_frame.h8
-rw-r--r--core/math/basis.cpp36
-rw-r--r--core/math/basis.h24
-rw-r--r--core/math/bvh_abb.h8
-rw-r--r--core/math/bvh_split.inc4
-rw-r--r--core/math/bvh_structs.inc4
-rw-r--r--core/math/bvh_tree.h3
-rw-r--r--core/math/color.cpp80
-rw-r--r--core/math/color.h19
-rw-r--r--core/math/convex_hull.cpp54
-rw-r--r--core/math/convex_hull.h12
-rw-r--r--core/math/delaunay_3d.h39
-rw-r--r--core/math/expression.cpp56
-rw-r--r--core/math/geometry_3d.cpp52
-rw-r--r--core/math/geometry_3d.h12
-rw-r--r--core/math/math_defs.h9
-rw-r--r--core/math/math_fieldwise.cpp47
-rw-r--r--core/math/math_funcs.h47
-rw-r--r--core/math/plane.cpp6
-rw-r--r--core/math/plane.h1
-rw-r--r--core/math/projection.cpp222
-rw-r--r--core/math/projection.h23
-rw-r--r--core/math/quaternion.cpp35
-rw-r--r--core/math/quaternion.h15
-rw-r--r--core/math/quick_hull.cpp19
-rw-r--r--core/math/random_number_generator.h2
-rw-r--r--core/math/rect2.cpp4
-rw-r--r--core/math/rect2.h13
-rw-r--r--core/math/rect2i.h2
-rw-r--r--core/math/transform_2d.cpp6
-rw-r--r--core/math/transform_2d.h1
-rw-r--r--core/math/transform_3d.cpp6
-rw-r--r--core/math/transform_3d.h2
-rw-r--r--core/math/triangle_mesh.cpp18
-rw-r--r--core/math/vector2.cpp4
-rw-r--r--core/math/vector2.h5
-rw-r--r--core/math/vector2i.h2
-rw-r--r--core/math/vector3.cpp14
-rw-r--r--core/math/vector3.h8
-rw-r--r--core/math/vector3i.cpp10
-rw-r--r--core/math/vector3i.h5
-rw-r--r--core/math/vector4.cpp17
-rw-r--r--core/math/vector4.h18
-rw-r--r--core/math/vector4i.cpp10
-rw-r--r--core/math/vector4i.h5
-rw-r--r--core/object/class_db.cpp21
-rw-r--r--core/object/make_virtuals.py18
-rw-r--r--core/object/method_bind.cpp4
-rw-r--r--core/object/method_bind.h56
-rw-r--r--core/object/object.cpp47
-rw-r--r--core/object/object.h52
-rw-r--r--core/object/ref_counted.cpp3
-rw-r--r--core/object/ref_counted.h2
-rw-r--r--core/object/script_language.cpp19
-rw-r--r--core/object/script_language_extension.h25
-rw-r--r--core/object/undo_redo.cpp4
-rw-r--r--core/object/undo_redo.h1
-rw-r--r--core/object/worker_thread_pool.cpp2
-rw-r--r--core/os/main_loop.cpp18
-rw-r--r--core/os/midi_driver.cpp5
-rw-r--r--core/os/mutex.cpp4
-rw-r--r--core/os/mutex.h27
-rw-r--r--core/os/os.cpp21
-rw-r--r--core/os/os.h11
-rw-r--r--core/os/pool_allocator.cpp8
-rw-r--r--core/os/rw_lock.h17
-rw-r--r--core/os/semaphore.h13
-rw-r--r--core/os/thread.cpp44
-rw-r--r--core/os/thread.h40
-rw-r--r--core/os/threaded_array_processor.h19
-rw-r--r--core/register_core_types.cpp9
-rw-r--r--core/string/optimized_translation.cpp51
-rw-r--r--core/string/optimized_translation.h1
-rw-r--r--core/string/translation.cpp140
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/translation_po.cpp17
-rw-r--r--core/string/translation_po.h1
-rw-r--r--core/string/ustring.cpp149
-rw-r--r--core/string/ustring.h8
-rw-r--r--core/templates/cowdata.h2
-rw-r--r--core/templates/hashfuncs.h5
-rw-r--r--core/templates/local_vector.h10
-rw-r--r--core/templates/paged_array.h2
-rw-r--r--core/templates/pooled_list.h7
-rw-r--r--core/templates/rid_owner.h11
-rw-r--r--core/templates/safe_list.h159
-rw-r--r--core/templates/safe_refcount.h139
-rw-r--r--core/variant/array.cpp8
-rw-r--r--core/variant/array.h3
-rw-r--r--core/variant/binder_common.h2
-rw-r--r--core/variant/callable.cpp39
-rw-r--r--core/variant/callable.h11
-rw-r--r--core/variant/container_type_validate.h15
-rw-r--r--core/variant/type_info.h8
-rw-r--r--core/variant/variant.cpp412
-rw-r--r--core/variant/variant.h1
-rw-r--r--core/variant/variant_call.cpp53
-rw-r--r--core/variant/variant_construct.cpp2
-rw-r--r--core/variant/variant_construct.h76
-rw-r--r--core/variant/variant_destruct.cpp5
-rw-r--r--core/variant/variant_destruct.h5
-rw-r--r--core/variant/variant_internal.h31
-rw-r--r--core/variant/variant_op.cpp12
-rw-r--r--core/variant/variant_parser.cpp2
-rw-r--r--core/variant/variant_setget.cpp2
-rw-r--r--core/variant/variant_setget.h8
-rw-r--r--core/variant/variant_utility.cpp17
180 files changed, 3430 insertions, 3032 deletions
diff --git a/core/SCsub b/core/SCsub
index d4462fa546..43deff3ad5 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -85,7 +85,7 @@ if env["builtin_zlib"]:
env_thirdparty.Prepend(CPPPATH=[thirdparty_zlib_dir])
# Needs to be available in main env too
env.Prepend(CPPPATH=[thirdparty_zlib_dir])
- if env["target"] == "debug":
+ if env.dev_build:
env_thirdparty.Append(CPPDEFINES=["ZLIB_DEBUG"])
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_zlib_sources)
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index cf9697be07..7aa5f4d06d 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -48,6 +48,15 @@ int Engine::get_physics_ticks_per_second() const {
return ips;
}
+void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
+ ERR_FAIL_COND_MSG(p_max_physics_steps <= 0, "Maximum number of physics steps per frame must be greater than 0.");
+ max_physics_steps_per_frame = p_max_physics_steps;
+}
+
+int Engine::get_max_physics_steps_per_frame() const {
+ return max_physics_steps_per_frame;
+}
+
void Engine::set_physics_jitter_fix(double p_threshold) {
if (p_threshold < 0) {
p_threshold = 0;
@@ -59,12 +68,12 @@ double Engine::get_physics_jitter_fix() const {
return physics_jitter_fix;
}
-void Engine::set_target_fps(int p_fps) {
- _target_fps = p_fps > 0 ? p_fps : 0;
+void Engine::set_max_fps(int p_fps) {
+ _max_fps = p_fps > 0 ? p_fps : 0;
}
-int Engine::get_target_fps() const {
- return _target_fps;
+int Engine::get_max_fps() const {
+ return _max_fps;
}
uint64_t Engine::get_frames_drawn() {
diff --git a/core/config/engine.h b/core/config/engine.h
index 121fd4d541..1b179c5727 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -60,9 +60,10 @@ private:
int ips = 60;
double physics_jitter_fix = 0.5;
double _fps = 1;
- int _target_fps = 0;
+ int _max_fps = 0;
double _time_scale = 1.0;
uint64_t _physics_frames = 0;
+ int max_physics_steps_per_frame = 8;
double _physics_interpolation_fraction = 0.0f;
bool abort_on_gpu_errors = false;
bool use_validation_layers = false;
@@ -93,11 +94,14 @@ public:
virtual void set_physics_ticks_per_second(int p_ips);
virtual int get_physics_ticks_per_second() const;
+ virtual void set_max_physics_steps_per_frame(int p_max_physics_steps);
+ virtual int get_max_physics_steps_per_frame() const;
+
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
- virtual void set_target_fps(int p_fps);
- virtual int get_target_fps() const;
+ virtual void set_max_fps(int p_fps);
+ virtual int get_max_fps() const;
virtual double get_frames_per_second() const { return _fps; }
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 6275502378..7aaa9a46b7 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -82,7 +82,7 @@ String ProjectSettings::get_imported_files_path() const {
// Returns the features that a project must have when opened with this build of Godot.
// This is used by the project manager to provide the initial_settings for config/features.
const PackedStringArray ProjectSettings::get_required_features() {
- PackedStringArray features = PackedStringArray();
+ PackedStringArray features;
features.append(VERSION_BRANCH);
#ifdef REAL_T_IS_DOUBLE
features.append("Double Precision");
@@ -101,19 +101,28 @@ const PackedStringArray ProjectSettings::_get_supported_features() {
features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH));
features.append(VERSION_FULL_CONFIG);
features.append(VERSION_FULL_BUILD);
- // For now, assume Vulkan is always supported.
- // This should be removed if it's possible to build the editor without Vulkan.
- features.append("Vulkan Clustered");
- features.append("Vulkan Mobile");
+
+#ifdef VULKAN_ENABLED
+ features.append("Forward Plus");
+ features.append("Mobile");
+#endif
+
+#ifdef GLES3_ENABLED
+ features.append("GL Compatibility");
+#endif
return features;
}
// Returns the features that this project needs but this build of Godot lacks.
const PackedStringArray ProjectSettings::get_unsupported_features(const PackedStringArray &p_project_features) {
- PackedStringArray unsupported_features = PackedStringArray();
+ PackedStringArray unsupported_features;
PackedStringArray supported_features = singleton->_get_supported_features();
for (int i = 0; i < p_project_features.size(); i++) {
if (!supported_features.has(p_project_features[i])) {
+ // Temporary compatibility code to ease upgrade to 4.0 beta 2+.
+ if (p_project_features[i].begins_with("Vulkan")) {
+ continue;
+ }
unsupported_features.append(p_project_features[i]);
}
}
@@ -144,8 +153,23 @@ const PackedStringArray ProjectSettings::_trim_to_supported_features(const Packe
#endif // TOOLS_ENABLED
String ProjectSettings::localize_path(const String &p_path) const {
- if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
- (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ if (resource_path.is_empty() || (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
+ return p_path.simplify_path();
+ }
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = p_path.find("://");
+ bool found = false;
+ if (p > 0) {
+ found = true;
+ for (int i = 0; i < p; i++) {
+ if (!is_ascii_alphanumeric_char(p_path[i])) {
+ found = false;
+ break;
+ }
+ }
+ }
+ if (found) {
return p_path.simplify_path();
}
@@ -595,7 +619,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
Error err = _setup(p_path, p_main_pack, p_upwards, p_ignore_override);
if (err == OK) {
- String custom_settings = GLOBAL_DEF("application/config/project_settings_override", "");
+ String custom_settings = GLOBAL_GET("application/config/project_settings_override");
if (!custom_settings.is_empty()) {
_load_settings_text(custom_settings);
}
@@ -776,7 +800,7 @@ Error ProjectSettings::save() {
return error;
}
-Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + ".");
@@ -786,7 +810,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
int count = 0;
- for (const KeyValue<String, List<String>> &E : props) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
count += E.value.size();
}
@@ -812,7 +836,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
file->store_32(count); //store how many properties are saved
}
- for (const KeyValue<String, List<String>> &E : props) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
for (const String &key : E.value) {
String k = key;
if (!E.key.is_empty()) {
@@ -844,7 +868,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const RBMap<S
return OK;
}
-Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<String, List<String>> &props, const CustomMap &p_custom, const String &p_custom_features) {
+Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<String, List<String>> &p_props, const CustomMap &p_custom, const String &p_custom_features) {
Error err;
Ref<FileAccess> file = FileAccess::open(p_file, FileAccess::WRITE, &err);
@@ -865,8 +889,8 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const RBMap<Str
}
file->store_string("\n");
- for (const KeyValue<String, List<String>> &E : props) {
- if (E.key != props.begin()->key) {
+ for (const KeyValue<String, List<String>> &E : p_props) {
+ if (E.key != p_props.begin()->key) {
file->store_string("\n");
}
@@ -909,7 +933,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
project_features = ProjectSettings::get_required_features();
}
// Check the rendering API.
- const String rendering_api = has_setting("rendering/quality/driver/driver_name") ? (String)get_setting("rendering/quality/driver/driver_name") : String();
+ const String rendering_api = has_setting("rendering/renderer/rendering_method") ? (String)get_setting("rendering/renderer/rendering_method") : String();
if (!rendering_api.is_empty()) {
// Add the rendering API as a project feature if it doesn't already exist.
if (!project_features.has(rendering_api)) {
@@ -971,7 +995,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
vclist.insert(vc);
}
- RBMap<String, List<String>> props;
+ RBMap<String, List<String>> save_props;
for (const _VCSort &E : vclist) {
String category = E.name;
@@ -985,24 +1009,24 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
category = category.substr(0, div);
name = name.substr(div + 1, name.size());
}
- props[category].push_back(name);
+ save_props[category].push_back(name);
}
- String custom_features;
+ String save_features;
for (int i = 0; i < p_custom_features.size(); i++) {
if (i > 0) {
- custom_features += ",";
+ save_features += ",";
}
String f = p_custom_features[i].strip_edges().replace("\"", "");
- custom_features += f;
+ save_features += f;
}
if (p_path.ends_with(".godot") || p_path.ends_with("override.cfg")) {
- return _save_settings_text(p_path, props, p_custom, custom_features);
+ return _save_settings_text(p_path, save_props, p_custom, save_features);
} else if (p_path.ends_with(".binary")) {
- return _save_settings_binary(p_path, props, p_custom, custom_features);
+ return _save_settings_binary(p_path, save_props, p_custom, save_features);
} else {
ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path + ".");
}
@@ -1013,7 +1037,7 @@ Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default, bool p_restar
if (!ProjectSettings::get_singleton()->has_setting(p_var)) {
ProjectSettings::get_singleton()->set(p_var, p_default);
}
- ret = ProjectSettings::get_singleton()->get(p_var);
+ ret = GLOBAL_GET(p_var);
ProjectSettings::get_singleton()->set_initial_value(p_var, p_default);
ProjectSettings::get_singleton()->set_builtin_order(p_var);
@@ -1139,6 +1163,7 @@ void ProjectSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_order", "name"), &ProjectSettings::get_order);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value"), &ProjectSettings::set_initial_value);
ClassDB::bind_method(D_METHOD("add_property_info", "hint"), &ProjectSettings::_add_property_info_bind);
+ ClassDB::bind_method(D_METHOD("set_restart_if_changed", "name", "restart"), &ProjectSettings::set_restart_if_changed);
ClassDB::bind_method(D_METHOD("clear", "name"), &ProjectSettings::clear);
ClassDB::bind_method(D_METHOD("localize_path", "path"), &ProjectSettings::localize_path);
ClassDB::bind_method(D_METHOD("globalize_path", "path"), &ProjectSettings::globalize_path);
@@ -1201,10 +1226,16 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF_BASIC("display/window/size/mode", 0);
+ custom_prop_info["display/window/size/mode"] = PropertyInfo(Variant::INT, "display/window/size/mode", PROPERTY_HINT_ENUM, "Windowed,Minimized,Maximized,Fullscreen,Exclusive Fullscreen");
+
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
GLOBAL_DEF_BASIC("display/window/size/borderless", false);
- GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
GLOBAL_DEF("display/window/size/always_on_top", false);
+ GLOBAL_DEF("display/window/size/transparent", false);
+ GLOBAL_DEF("display/window/size/extend_to_title", false);
+ GLOBAL_DEF("display/window/size/no_focus", false);
+
GLOBAL_DEF("display/window/size/window_width_override", 0);
custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
GLOBAL_DEF("display/window/size/window_height_override", 0);
@@ -1215,12 +1246,12 @@ ProjectSettings::ProjectSettings() {
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");
- GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f);
- custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01");
- GLOBAL_DEF_RST("audio/general/3d_panning_strength", 1.0f);
- custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,4,0.01");
+ GLOBAL_DEF_RST("audio/general/2d_panning_strength", 0.5f);
+ custom_prop_info["audio/general/2d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/2d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01");
+ GLOBAL_DEF_RST("audio/general/3d_panning_strength", 0.5f);
+ custom_prop_info["audio/general/3d_panning_strength"] = PropertyInfo(Variant::FLOAT, "audio/general/3d_panning_strength", PROPERTY_HINT_RANGE, "0,2,0.01");
- PackedStringArray extensions = PackedStringArray();
+ PackedStringArray extensions;
extensions.push_back("gd");
if (Engine::get_singleton()->has_singleton("GodotSharp")) {
extensions.push_back("cs");
@@ -1245,6 +1276,7 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("physics/2d/run_on_separate_thread", false);
GLOBAL_DEF("physics/3d/run_on_separate_thread", false);
+ GLOBAL_DEF("debug/disable_touch", 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");
@@ -1261,6 +1293,22 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("compression/formats/gzip/compression_level", Compression::gzip_level);
custom_prop_info["compression/formats/gzip/compression_level"] = PropertyInfo(Variant::INT, "compression/formats/gzip/compression_level", PROPERTY_HINT_RANGE, "-1,9,1");
+ GLOBAL_DEF("debug/settings/crash_handler/message",
+ String("Please include this when reporting the bug to the project developer."));
+ GLOBAL_DEF("debug/settings/crash_handler/message.editor",
+ String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues"));
+ GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
+ GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
+ GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false);
+
+ GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers.
+
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/block_size_kb", 256);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/max_size_mb", 128);
+ GLOBAL_DEF("rendering/rendering_device/staging_buffer/texture_upload_region_size_px", 64);
+ GLOBAL_DEF("rendering/rendering_device/vulkan/max_descriptors_per_pool", 64);
+
// These properties will not show up in the dialog nor in the documentation. If you want to exclude whole groups, see _get_property_list() method.
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index ba48adff6a..1fe34cb4fd 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -253,6 +253,10 @@ Error OS::shell_open(String p_uri) {
return ::OS::get_singleton()->shell_open(p_uri);
}
+String OS::read_string_from_stdin(bool p_block) {
+ return ::OS::get_singleton()->get_stdin_string(true);
+}
+
int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) {
List<String> args;
for (int i = 0; i < p_arguments.size(); i++) {
@@ -330,6 +334,10 @@ String OS::get_version() const {
return ::OS::get_singleton()->get_version();
}
+Vector<String> OS::get_video_adapter_driver_info() const {
+ return ::OS::get_singleton()->get_video_adapter_driver_info();
+}
+
Vector<String> OS::get_cmdline_args() {
List<String> cmdline = ::OS::get_singleton()->get_cmdline_args();
Vector<String> cmdlinev;
@@ -425,10 +433,6 @@ void OS::delay_msec(int p_msec) const {
::OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000);
}
-bool OS::can_use_threads() const {
- return ::OS::get_singleton()->can_use_threads();
-}
-
bool OS::is_userfs_persistent() const {
return ::OS::get_singleton()->is_userfs_persistent();
}
@@ -530,6 +534,7 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_fonts"), &OS::get_system_fonts);
ClassDB::bind_method(D_METHOD("get_system_font_path", "font_name", "bold", "italic"), &OS::get_system_font_path, DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path);
+ ClassDB::bind_method(D_METHOD("read_string_from_stdin", "block"), &OS::read_string_from_stdin, DEFVAL(true));
ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false));
ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance);
@@ -548,6 +553,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
+ ClassDB::bind_method(D_METHOD("get_video_adapter_driver_info"), &OS::get_video_adapter_driver_info);
+
ClassDB::bind_method(D_METHOD("set_restart_on_exit", "restart", "arguments"), &OS::set_restart_on_exit, DEFVAL(Vector<String>()));
ClassDB::bind_method(D_METHOD("is_restart_on_exit_set"), &OS::is_restart_on_exit_set);
ClassDB::bind_method(D_METHOD("get_restart_on_exit_arguments"), &OS::get_restart_on_exit_arguments);
@@ -561,8 +568,6 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_userfs_persistent"), &OS::is_userfs_persistent);
ClassDB::bind_method(D_METHOD("is_stdout_verbose"), &OS::is_stdout_verbose);
- ClassDB::bind_method(D_METHOD("can_use_threads"), &OS::can_use_threads);
-
ClassDB::bind_method(D_METHOD("is_debug_build"), &OS::is_debug_build);
ClassDB::bind_method(D_METHOD("get_static_memory_usage"), &OS::get_static_memory_usage);
@@ -600,8 +605,8 @@ void OS::_bind_methods() {
ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false);
ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900);
- BIND_ENUM_CONSTANT(VIDEO_DRIVER_VULKAN);
- BIND_ENUM_CONSTANT(VIDEO_DRIVER_OPENGL_3);
+ BIND_ENUM_CONSTANT(RENDERING_DRIVER_VULKAN);
+ BIND_ENUM_CONSTANT(RENDERING_DRIVER_OPENGL3);
BIND_ENUM_CONSTANT(DAY_SUNDAY);
BIND_ENUM_CONSTANT(DAY_MONDAY);
@@ -709,6 +714,17 @@ Vector<Point2> Geometry2D::convex_hull(const Vector<Point2> &p_points) {
return ::Geometry2D::convex_hull(p_points);
}
+TypedArray<PackedVector2Array> Geometry2D::decompose_polygon_in_convex(const Vector<Vector2> &p_polygon) {
+ Vector<Vector<Point2>> decomp = ::Geometry2D::decompose_polygon_in_convex(p_polygon);
+
+ TypedArray<PackedVector2Array> ret;
+
+ for (int i = 0; i < decomp.size(); ++i) {
+ ret.push_back(decomp[i]);
+ }
+ return ret;
+}
+
TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b);
@@ -810,14 +826,13 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) {
::Geometry2D::make_atlas(rects, result, size);
- Size2 r_size = size;
Vector<Point2> r_result;
for (int i = 0; i < result.size(); i++) {
r_result.push_back(result[i]);
}
ret["points"] = r_result;
- ret["size"] = r_size;
+ ret["size"] = size;
return ret;
}
@@ -841,6 +856,7 @@ void Geometry2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &Geometry2D::triangulate_polygon);
ClassDB::bind_method(D_METHOD("triangulate_delaunay", "points"), &Geometry2D::triangulate_delaunay);
ClassDB::bind_method(D_METHOD("convex_hull", "points"), &Geometry2D::convex_hull);
+ ClassDB::bind_method(D_METHOD("decompose_polygon_in_convex", "polygon"), &Geometry2D::decompose_polygon_in_convex);
ClassDB::bind_method(D_METHOD("merge_polygons", "polygon_a", "polygon_b"), &Geometry2D::merge_polygons);
ClassDB::bind_method(D_METHOD("clip_polygons", "polygon_a", "polygon_b"), &Geometry2D::clip_polygons);
@@ -992,636 +1008,6 @@ void Geometry3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &Geometry3D::clip_polygon);
}
-////// File //////
-
-Error File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
- Error err = open(p_path, p_mode_flags);
- if (err) {
- return err;
- }
-
- Ref<FileAccessEncrypted> fae;
- fae.instantiate();
- err = fae->open_and_parse(f, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
- if (err) {
- close();
- return err;
- }
- f = fae;
- return OK;
-}
-
-Error File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
- Error err = open(p_path, p_mode_flags);
- if (err) {
- return err;
- }
-
- Ref<FileAccessEncrypted> fae;
- fae.instantiate();
- err = fae->open_and_parse_password(f, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
- if (err) {
- close();
- return err;
- }
-
- f = fae;
- return OK;
-}
-
-Error File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
- Ref<FileAccessCompressed> fac;
- fac.instantiate();
- fac->configure("GCPF", (Compression::Mode)p_compress_mode);
-
- Error err = fac->_open(p_path, p_mode_flags);
-
- if (err) {
- return err;
- }
-
- f = fac;
- return OK;
-}
-
-Error File::open(const String &p_path, ModeFlags p_mode_flags) {
- Error err;
- f = FileAccess::open(p_path, p_mode_flags, &err);
- if (f.is_valid()) {
- f->set_big_endian(big_endian);
- }
- return err;
-}
-
-void File::flush() {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before flushing.");
- f->flush();
-}
-
-void File::close() {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened.");
- f.unref();
-}
-
-bool File::is_open() const {
- return f != nullptr;
-}
-
-String File::get_path() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
- return f->get_path();
-}
-
-String File::get_path_absolute() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
- return f->get_path_absolute();
-}
-
-void File::seek(int64_t p_position) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer.");
- f->seek(p_position);
-}
-
-void File::seek_end(int64_t p_position) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- f->seek_end(p_position);
-}
-
-uint64_t File::get_position() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_position();
-}
-
-uint64_t File::get_length() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_length();
-}
-
-bool File::eof_reached() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use, or is lacking read-write permission.");
- return f->eof_reached();
-}
-
-uint8_t File::get_8() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_8();
-}
-
-uint16_t File::get_16() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_16();
-}
-
-uint32_t File::get_32() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_32();
-}
-
-uint64_t File::get_64() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_64();
-}
-
-float File::get_float() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_float();
-}
-
-double File::get_double() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_double();
-}
-
-real_t File::get_real() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), 0, "File must be opened before use, or is lacking read-write permission.");
- return f->get_real();
-}
-
-Vector<uint8_t> File::get_buffer(int64_t p_length) const {
- Vector<uint8_t> data;
- ERR_FAIL_COND_V_MSG(f.is_null(), data, "File must be opened before use, or is lacking read-write permission.");
-
- ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
- if (p_length == 0) {
- return data;
- }
-
- Error err = data.resize(p_length);
- ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
-
- uint8_t *w = data.ptrw();
- int64_t len = f->get_buffer(&w[0], p_length);
-
- if (len < p_length) {
- data.resize(len);
- }
-
- return data;
-}
-
-String File::get_as_text(bool p_skip_cr) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
-
- uint64_t original_pos = f->get_position();
- const_cast<FileAccess *>(*f)->seek(0);
-
- String text = f->get_as_utf8_string(p_skip_cr);
-
- const_cast<FileAccess *>(*f)->seek(original_pos);
-
- return text;
-}
-
-String File::get_md5(const String &p_path) const {
- return FileAccess::get_md5(p_path);
-}
-
-String File::get_sha256(const String &p_path) const {
- return FileAccess::get_sha256(p_path);
-}
-
-String File::get_line() const {
- ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
- return f->get_line();
-}
-
-Vector<String> File::get_csv_line(const String &p_delim) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), Vector<String>(), "File must be opened before use, or is lacking read-write permission.");
- return f->get_csv_line(p_delim);
-}
-
-/**< use this for files WRITTEN in _big_ endian machines (i.e. amiga/mac)
- * It's not about the current CPU type but file formats.
- * These flags get reset to false (little endian) on each open
- */
-
-void File::set_big_endian(bool p_big_endian) {
- big_endian = p_big_endian;
- if (f.is_valid()) {
- f->set_big_endian(p_big_endian);
- }
-}
-
-bool File::is_big_endian() {
- return big_endian;
-}
-
-Error File::get_error() const {
- if (f.is_null()) {
- return ERR_UNCONFIGURED;
- }
- return f->get_error();
-}
-
-void File::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_8(p_dest);
-}
-
-void File::store_16(uint16_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_16(p_dest);
-}
-
-void File::store_32(uint32_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_32(p_dest);
-}
-
-void File::store_64(uint64_t p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_64(p_dest);
-}
-
-void File::store_float(float p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_float(p_dest);
-}
-
-void File::store_double(double p_dest) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_double(p_dest);
-}
-
-void File::store_real(real_t p_real) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_real(p_real);
-}
-
-void File::store_string(const String &p_string) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_string(p_string);
-}
-
-void File::store_pascal_string(const String &p_string) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- f->store_pascal_string(p_string);
-}
-
-String File::get_pascal_string() {
- ERR_FAIL_COND_V_MSG(f.is_null(), "", "File must be opened before use, or is lacking read-write permission.");
-
- return f->get_pascal_string();
-}
-
-void File::store_line(const String &p_string) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- f->store_line(p_string);
-}
-
-void File::store_csv_line(const Vector<String> &p_values, const String &p_delim) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- f->store_csv_line(p_values, p_delim);
-}
-
-void File::store_buffer(const Vector<uint8_t> &p_buffer) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
-
- uint64_t len = p_buffer.size();
- if (len == 0) {
- return;
- }
-
- const uint8_t *r = p_buffer.ptr();
-
- f->store_buffer(&r[0], len);
-}
-
-bool File::file_exists(const String &p_name) {
- return FileAccess::exists(p_name);
-}
-
-void File::store_var(const Variant &p_var, bool p_full_objects) {
- ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use, or is lacking read-write permission.");
- int len;
- Error err = encode_variant(p_var, nullptr, len, p_full_objects);
- ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
-
- Vector<uint8_t> buff;
- buff.resize(len);
-
- uint8_t *w = buff.ptrw();
- err = encode_variant(p_var, &w[0], len, p_full_objects);
- ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
-
- store_32(len);
- store_buffer(buff);
-}
-
-Variant File::get_var(bool p_allow_objects) const {
- ERR_FAIL_COND_V_MSG(f.is_null(), Variant(), "File must be opened before use, or is lacking read-write permission.");
- uint32_t len = get_32();
- Vector<uint8_t> buff = get_buffer(len);
- ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
-
- const uint8_t *r = buff.ptr();
-
- Variant v;
- Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
- ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
-
- return v;
-}
-
-uint64_t File::get_modified_time(const String &p_file) const {
- return FileAccess::get_modified_time(p_file);
-}
-
-void File::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open_encrypted", "path", "mode_flags", "key"), &File::open_encrypted);
- ClassDB::bind_method(D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &File::open_encrypted_pass);
- 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);
- ClassDB::bind_method(D_METHOD("is_open"), &File::is_open);
- ClassDB::bind_method(D_METHOD("seek", "position"), &File::seek);
- ClassDB::bind_method(D_METHOD("seek_end", "position"), &File::seek_end, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_position"), &File::get_position);
- ClassDB::bind_method(D_METHOD("get_length"), &File::get_length);
- ClassDB::bind_method(D_METHOD("eof_reached"), &File::eof_reached);
- ClassDB::bind_method(D_METHOD("get_8"), &File::get_8);
- ClassDB::bind_method(D_METHOD("get_16"), &File::get_16);
- ClassDB::bind_method(D_METHOD("get_32"), &File::get_32);
- ClassDB::bind_method(D_METHOD("get_64"), &File::get_64);
- ClassDB::bind_method(D_METHOD("get_float"), &File::get_float);
- ClassDB::bind_method(D_METHOD("get_double"), &File::get_double);
- ClassDB::bind_method(D_METHOD("get_real"), &File::get_real);
- ClassDB::bind_method(D_METHOD("get_buffer", "length"), &File::get_buffer);
- ClassDB::bind_method(D_METHOD("get_line"), &File::get_line);
- ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &File::get_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &File::get_as_text, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_md5", "path"), &File::get_md5);
- ClassDB::bind_method(D_METHOD("get_sha256", "path"), &File::get_sha256);
- ClassDB::bind_method(D_METHOD("is_big_endian"), &File::is_big_endian);
- ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &File::set_big_endian);
- ClassDB::bind_method(D_METHOD("get_error"), &File::get_error);
- ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &File::get_var, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("store_8", "value"), &File::store_8);
- ClassDB::bind_method(D_METHOD("store_16", "value"), &File::store_16);
- ClassDB::bind_method(D_METHOD("store_32", "value"), &File::store_32);
- ClassDB::bind_method(D_METHOD("store_64", "value"), &File::store_64);
- ClassDB::bind_method(D_METHOD("store_float", "value"), &File::store_float);
- ClassDB::bind_method(D_METHOD("store_double", "value"), &File::store_double);
- ClassDB::bind_method(D_METHOD("store_real", "value"), &File::store_real);
- ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &File::store_buffer);
- ClassDB::bind_method(D_METHOD("store_line", "line"), &File::store_line);
- ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &File::store_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("store_string", "string"), &File::store_string);
- ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &File::store_var, DEFVAL(false));
-
- ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &File::store_pascal_string);
- ClassDB::bind_method(D_METHOD("get_pascal_string"), &File::get_pascal_string);
-
- ClassDB::bind_static_method("File", D_METHOD("file_exists", "path"), &File::file_exists);
- ClassDB::bind_method(D_METHOD("get_modified_time", "file"), &File::get_modified_time);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
-
- BIND_ENUM_CONSTANT(READ);
- BIND_ENUM_CONSTANT(WRITE);
- BIND_ENUM_CONSTANT(READ_WRITE);
- BIND_ENUM_CONSTANT(WRITE_READ);
-
- BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
- BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
- BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
- BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
-}
-
-////// Directory //////
-
-Error Directory::open(const String &p_path) {
- Error err;
- Ref<DirAccess> alt = DirAccess::open(p_path, &err);
- if (alt.is_null()) {
- return err;
- }
- d = alt;
- dir_open = true;
-
- return OK;
-}
-
-bool Directory::is_open() const {
- return d.is_valid() && dir_open;
-}
-
-Error Directory::list_dir_begin() {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->list_dir_begin();
-}
-
-String Directory::get_next() {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
-
- String next = d->get_next();
- while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && d->current_is_hidden()))) {
- next = d->get_next();
- }
- return next;
-}
-
-bool Directory::current_is_dir() const {
- ERR_FAIL_COND_V_MSG(!is_open(), false, "Directory must be opened before use.");
- return d->current_is_dir();
-}
-
-void Directory::list_dir_end() {
- ERR_FAIL_COND_MSG(!is_open(), "Directory must be opened before use.");
- d->list_dir_end();
-}
-
-PackedStringArray Directory::get_files() {
- return _get_contents(false);
-}
-
-PackedStringArray Directory::get_directories() {
- return _get_contents(true);
-}
-
-PackedStringArray Directory::_get_contents(bool p_directories) {
- PackedStringArray ret;
- ERR_FAIL_COND_V_MSG(!is_open(), ret, "Directory must be opened before use.");
-
- list_dir_begin();
- String s = get_next();
- while (!s.is_empty()) {
- if (current_is_dir() == p_directories) {
- ret.append(s);
- }
- s = get_next();
- }
-
- ret.sort();
- return ret;
-}
-
-void Directory::set_include_navigational(bool p_enable) {
- include_navigational = p_enable;
-}
-
-bool Directory::get_include_navigational() const {
- return include_navigational;
-}
-
-void Directory::set_include_hidden(bool p_enable) {
- include_hidden = p_enable;
-}
-
-bool Directory::get_include_hidden() const {
- return include_hidden;
-}
-
-int Directory::get_drive_count() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_drive_count();
-}
-
-String Directory::get_drive(int p_drive) {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
- return d->get_drive(p_drive);
-}
-
-int Directory::get_current_drive() {
- ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use.");
- return d->get_current_drive();
-}
-
-Error Directory::change_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- Error err = d->change_dir(p_dir);
-
- if (err != OK) {
- return err;
- }
- dir_open = true;
-
- return OK;
-}
-
-String Directory::get_current_dir() {
- ERR_FAIL_COND_V_MSG(!is_open(), "", "Directory must be opened before use.");
- return d->get_current_dir();
-}
-
-Error Directory::make_dir(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
- return da->make_dir(p_dir);
- }
- return d->make_dir(p_dir);
-}
-
-Error Directory::make_dir_recursive(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), ERR_UNCONFIGURED, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
- return da->make_dir_recursive(p_dir);
- }
- return d->make_dir_recursive(p_dir);
-}
-
-bool Directory::file_exists(String p_file) {
- ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
- if (!p_file.is_relative_path()) {
- return FileAccess::exists(p_file);
- }
- return d->file_exists(p_file);
-}
-
-bool Directory::dir_exists(String p_dir) {
- ERR_FAIL_COND_V_MSG(d.is_null(), false, "Directory is not configured properly.");
- if (!p_dir.is_relative_path()) {
- return DirAccess::exists(p_dir);
- }
- return d->dir_exists(p_dir);
-}
-
-uint64_t Directory::get_space_left() {
- ERR_FAIL_COND_V_MSG(d.is_null(), 0, "Directory must be opened before use.");
- return d->get_space_left() / 1024 * 1024; // Truncate to closest MiB.
-}
-
-Error Directory::copy(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- return d->copy(p_from, p_to);
-}
-
-Error Directory::rename(String p_from, String p_to) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- ERR_FAIL_COND_V_MSG(p_from.is_empty() || p_from == "." || p_from == "..", ERR_INVALID_PARAMETER, "Invalid path to rename.");
-
- if (!p_from.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_from);
- ERR_FAIL_COND_V_MSG(!da->file_exists(p_from) && !da->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- return da->rename(p_from, p_to);
- }
-
- ERR_FAIL_COND_V_MSG(!d->file_exists(p_from) && !d->dir_exists(p_from), ERR_DOES_NOT_EXIST, "File or directory does not exist.");
- return d->rename(p_from, p_to);
-}
-
-Error Directory::remove(String p_name) {
- ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use.");
- if (!p_name.is_relative_path()) {
- Ref<DirAccess> da = DirAccess::create_for_path(p_name);
- return da->remove(p_name);
- }
-
- return d->remove(p_name);
-}
-
-void Directory::_bind_methods() {
- ClassDB::bind_method(D_METHOD("open", "path"), &Directory::open);
- ClassDB::bind_method(D_METHOD("list_dir_begin"), &Directory::list_dir_begin, DEFVAL(false), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_next"), &Directory::get_next);
- ClassDB::bind_method(D_METHOD("current_is_dir"), &Directory::current_is_dir);
- ClassDB::bind_method(D_METHOD("list_dir_end"), &Directory::list_dir_end);
- ClassDB::bind_method(D_METHOD("get_files"), &Directory::get_files);
- ClassDB::bind_method(D_METHOD("get_directories"), &Directory::get_directories);
- ClassDB::bind_method(D_METHOD("get_drive_count"), &Directory::get_drive_count);
- ClassDB::bind_method(D_METHOD("get_drive", "idx"), &Directory::get_drive);
- ClassDB::bind_method(D_METHOD("get_current_drive"), &Directory::get_current_drive);
- ClassDB::bind_method(D_METHOD("change_dir", "todir"), &Directory::change_dir);
- ClassDB::bind_method(D_METHOD("get_current_dir"), &Directory::get_current_dir);
- ClassDB::bind_method(D_METHOD("make_dir", "path"), &Directory::make_dir);
- ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &Directory::make_dir_recursive);
- ClassDB::bind_method(D_METHOD("file_exists", "path"), &Directory::file_exists);
- ClassDB::bind_method(D_METHOD("dir_exists", "path"), &Directory::dir_exists);
- ClassDB::bind_method(D_METHOD("get_space_left"), &Directory::get_space_left);
- ClassDB::bind_method(D_METHOD("copy", "from", "to"), &Directory::copy);
- ClassDB::bind_method(D_METHOD("rename", "from", "to"), &Directory::rename);
- ClassDB::bind_method(D_METHOD("remove", "path"), &Directory::remove);
-
- ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &Directory::set_include_navigational);
- ClassDB::bind_method(D_METHOD("get_include_navigational"), &Directory::get_include_navigational);
- ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &Directory::set_include_hidden);
- ClassDB::bind_method(D_METHOD("get_include_hidden"), &Directory::get_include_hidden);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
-}
-
-Directory::Directory() {
- d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
-}
-
////// Marshalls //////
Marshalls *Marshalls::singleton = nullptr;
@@ -2091,6 +1477,14 @@ int Engine::get_physics_ticks_per_second() const {
return ::Engine::get_singleton()->get_physics_ticks_per_second();
}
+void Engine::set_max_physics_steps_per_frame(int p_max_physics_steps) {
+ ::Engine::get_singleton()->set_max_physics_steps_per_frame(p_max_physics_steps);
+}
+
+int Engine::get_max_physics_steps_per_frame() const {
+ return ::Engine::get_singleton()->get_max_physics_steps_per_frame();
+}
+
void Engine::set_physics_jitter_fix(double p_threshold) {
::Engine::get_singleton()->set_physics_jitter_fix(p_threshold);
}
@@ -2103,12 +1497,12 @@ double Engine::get_physics_interpolation_fraction() const {
return ::Engine::get_singleton()->get_physics_interpolation_fraction();
}
-void Engine::set_target_fps(int p_fps) {
- ::Engine::get_singleton()->set_target_fps(p_fps);
+void Engine::set_max_fps(int p_fps) {
+ ::Engine::get_singleton()->set_max_fps(p_fps);
}
-int Engine::get_target_fps() const {
- return ::Engine::get_singleton()->get_target_fps();
+int Engine::get_max_fps() const {
+ return ::Engine::get_singleton()->get_max_fps();
}
double Engine::get_frames_per_second() const {
@@ -2242,11 +1636,13 @@ bool Engine::is_printing_error_messages() const {
void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_physics_ticks_per_second", "physics_ticks_per_second"), &Engine::set_physics_ticks_per_second);
ClassDB::bind_method(D_METHOD("get_physics_ticks_per_second"), &Engine::get_physics_ticks_per_second);
+ ClassDB::bind_method(D_METHOD("set_max_physics_steps_per_frame", "max_physics_steps"), &Engine::set_max_physics_steps_per_frame);
+ ClassDB::bind_method(D_METHOD("get_max_physics_steps_per_frame"), &Engine::get_max_physics_steps_per_frame);
ClassDB::bind_method(D_METHOD("set_physics_jitter_fix", "physics_jitter_fix"), &Engine::set_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_jitter_fix"), &Engine::get_physics_jitter_fix);
ClassDB::bind_method(D_METHOD("get_physics_interpolation_fraction"), &Engine::get_physics_interpolation_fraction);
- ClassDB::bind_method(D_METHOD("set_target_fps", "target_fps"), &Engine::set_target_fps);
- ClassDB::bind_method(D_METHOD("get_target_fps"), &Engine::get_target_fps);
+ ClassDB::bind_method(D_METHOD("set_max_fps", "max_fps"), &Engine::set_max_fps);
+ ClassDB::bind_method(D_METHOD("get_max_fps"), &Engine::get_max_fps);
ClassDB::bind_method(D_METHOD("set_time_scale", "time_scale"), &Engine::set_time_scale);
ClassDB::bind_method(D_METHOD("get_time_scale"), &Engine::get_time_scale);
@@ -2289,7 +1685,8 @@ void Engine::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages");
ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_ticks_per_second"), "set_physics_ticks_per_second", "get_physics_ticks_per_second");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "target_fps"), "set_target_fps", "get_target_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_physics_steps_per_frame"), "set_max_physics_steps_per_frame", "get_max_physics_steps_per_frame");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_fps"), "set_max_fps", "get_max_fps");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "physics_jitter_fix"), "set_physics_jitter_fix", "get_physics_jitter_fix");
}
diff --git a/core/core_bind.h b/core/core_bind.h
index 0f85e473a5..748ecb4929 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -32,9 +32,6 @@
#define CORE_BIND_H
#include "core/debugger/engine_profiler.h"
-#include "core/io/compression.h"
-#include "core/io/dir_access.h"
-#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
@@ -127,9 +124,9 @@ protected:
static OS *singleton;
public:
- enum VideoDriver {
- VIDEO_DRIVER_VULKAN,
- VIDEO_DRIVER_OPENGL_3,
+ enum RenderingDriver {
+ RENDERING_DRIVER_VULKAN,
+ RENDERING_DRIVER_OPENGL3,
};
enum Weekday {
@@ -175,6 +172,7 @@ public:
Vector<String> get_system_fonts() const;
String get_system_font_path(const String &p_font_name, bool p_bold = false, bool p_italic = false) const;
String get_executable_path() const;
+ String read_string_from_stdin(bool p_block = true);
int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false);
int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false);
int create_instance(const Vector<String> &p_arguments);
@@ -198,6 +196,8 @@ public:
Vector<String> get_cmdline_args();
Vector<String> get_cmdline_user_args();
+ Vector<String> get_video_adapter_driver_info() const;
+
String get_locale() const;
String get_locale_language() const;
@@ -221,8 +221,6 @@ public:
uint64_t get_ticks_msec() const;
uint64_t get_ticks_usec() const;
- bool can_use_threads() const;
-
bool is_userfs_persistent() const;
bool is_stdout_verbose() const;
@@ -289,6 +287,7 @@ public:
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
Vector<int> triangulate_delaunay(const Vector<Vector2> &p_points);
Vector<Point2> convex_hull(const Vector<Point2> &p_points);
+ TypedArray<PackedVector2Array> decompose_polygon_in_convex(const Vector<Vector2> &p_polygon);
enum PolyBooleanOperation {
OPERATION_UNION,
@@ -355,156 +354,6 @@ public:
Geometry3D() { singleton = this; }
};
-class File : public RefCounted {
- GDCLASS(File, RefCounted);
-
- Ref<FileAccess> f;
- bool big_endian = false;
-
-protected:
- static void _bind_methods();
-
-public:
- enum ModeFlags {
- READ = 1,
- WRITE = 2,
- READ_WRITE = 3,
- WRITE_READ = 7,
- };
-
- enum CompressionMode {
- COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
- COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
- COMPRESSION_ZSTD = Compression::MODE_ZSTD,
- COMPRESSION_GZIP = Compression::MODE_GZIP
- };
-
- Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
- Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
- 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.
-
- String get_path() const; // Returns the path for the current open file.
- String get_path_absolute() const; // Returns the absolute path for the current open file.
-
- void seek(int64_t p_position); // Seek to a given position.
- void seek_end(int64_t p_position = 0); // Seek from the end of file.
- uint64_t get_position() const; // Get position in the file.
- uint64_t get_length() const; // Get size of the file.
-
- bool eof_reached() const; // Reading passed EOF.
-
- uint8_t get_8() const; // Get a byte.
- uint16_t get_16() const; // Get 16 bits uint.
- uint32_t get_32() const; // Get 32 bits uint.
- uint64_t get_64() const; // Get 64 bits uint.
-
- float get_float() const;
- double get_double() const;
- real_t get_real() const;
-
- Variant get_var(bool p_allow_objects = false) const;
-
- Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes.
- String get_line() const;
- Vector<String> get_csv_line(const String &p_delim = ",") const;
- String get_as_text(bool p_skip_cr = false) const;
- String get_md5(const String &p_path) const;
- String get_sha256(const String &p_path) const;
-
- /*
- * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac).
- * It's not about the current CPU type but file formats.
- * This flag gets reset to `false` (little endian) on each open.
- */
- void set_big_endian(bool p_big_endian);
- bool is_big_endian();
-
- Error get_error() const; // Get last error.
-
- void store_8(uint8_t p_dest); // Store a byte.
- void store_16(uint16_t p_dest); // Store 16 bits uint.
- void store_32(uint32_t p_dest); // Store 32 bits uint.
- void store_64(uint64_t p_dest); // Store 64 bits uint.
-
- void store_float(float p_dest);
- void store_double(double p_dest);
- void store_real(real_t p_real);
-
- void store_string(const String &p_string);
- void store_line(const String &p_string);
- void store_csv_line(const Vector<String> &p_values, const String &p_delim = ",");
-
- virtual void store_pascal_string(const String &p_string);
- virtual String get_pascal_string();
-
- void store_buffer(const Vector<uint8_t> &p_buffer); // Store an array of bytes.
-
- void store_var(const Variant &p_var, bool p_full_objects = false);
-
- static bool file_exists(const String &p_name); // Return true if a file exists.
-
- uint64_t get_modified_time(const String &p_file) const;
-
- File() {}
-};
-
-class Directory : public RefCounted {
- GDCLASS(Directory, RefCounted);
- Ref<DirAccess> d;
-
- bool dir_open = false;
- bool include_navigational = false;
- bool include_hidden = false;
-
-protected:
- static void _bind_methods();
-
-public:
- Error open(const String &p_path);
-
- bool is_open() const;
-
- Error list_dir_begin();
- String get_next();
- bool current_is_dir() const;
- void list_dir_end();
-
- PackedStringArray get_files();
- PackedStringArray get_directories();
- PackedStringArray _get_contents(bool p_directories);
-
- void set_include_navigational(bool p_enable);
- bool get_include_navigational() const;
- void set_include_hidden(bool p_enable);
- bool get_include_hidden() const;
-
- int get_drive_count();
- String get_drive(int p_drive);
- int get_current_drive();
-
- Error change_dir(String p_dir); // Can be relative or absolute, return false on success.
- String get_current_dir(); // Return current dir location.
-
- Error make_dir(String p_dir);
- Error make_dir_recursive(String p_dir);
-
- bool file_exists(String p_file);
- bool dir_exists(String p_dir);
-
- uint64_t get_space_left();
-
- Error copy(String p_from, String p_to);
- Error rename(String p_from, String p_to);
- Error remove(String p_name);
-
- Directory();
-};
-
class Marshalls : public Object {
GDCLASS(Marshalls, Object);
@@ -637,12 +486,15 @@ public:
void set_physics_ticks_per_second(int p_ips);
int get_physics_ticks_per_second() const;
+ void set_max_physics_steps_per_frame(int p_max_physics_steps);
+ int get_max_physics_steps_per_frame() const;
+
void set_physics_jitter_fix(double p_threshold);
double get_physics_jitter_fix() const;
double get_physics_interpolation_fraction() const;
- void set_target_fps(int p_fps);
- int get_target_fps() const;
+ void set_max_fps(int p_fps);
+ int get_max_fps() const;
double get_frames_per_second() const;
uint64_t get_physics_frames() const;
@@ -729,7 +581,7 @@ VARIANT_ENUM_CAST(core_bind::ResourceLoader::CacheMode);
VARIANT_BITFIELD_CAST(core_bind::ResourceSaver::SaverFlags);
-VARIANT_ENUM_CAST(core_bind::OS::VideoDriver);
+VARIANT_ENUM_CAST(core_bind::OS::RenderingDriver);
VARIANT_ENUM_CAST(core_bind::OS::Weekday);
VARIANT_ENUM_CAST(core_bind::OS::Month);
VARIANT_ENUM_CAST(core_bind::OS::SystemDir);
@@ -738,9 +590,6 @@ VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyBooleanOperation);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyJoinType);
VARIANT_ENUM_CAST(core_bind::Geometry2D::PolyEndType);
-VARIANT_ENUM_CAST(core_bind::File::ModeFlags);
-VARIANT_ENUM_CAST(core_bind::File::CompressionMode);
-
VARIANT_ENUM_CAST(core_bind::Thread::Priority);
#endif // CORE_BIND_H
diff --git a/core/core_builders.py b/core/core_builders.py
index b07daa80ae..b0a3b85d58 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -2,6 +2,7 @@
All such functions are invoked in a subprocess on Windows to prevent build flakiness.
"""
+import zlib
from platform_methods import subprocess_main
@@ -33,7 +34,6 @@ def make_certs_header(target, source, env):
g = open(dst, "w", encoding="utf-8")
buf = f.read()
decomp_size = len(buf)
- import zlib
# Use maximum zlib compression level to further reduce file size
# (at the cost of initial build times).
@@ -208,7 +208,7 @@ def make_license_header(target, source, env):
from collections import OrderedDict
- projects = OrderedDict()
+ projects: dict = OrderedDict()
license_list = []
with open(src_copyright, "r", encoding="utf-8") as copyright_file:
@@ -230,7 +230,7 @@ def make_license_header(target, source, env):
part = {}
reader.next_line()
- data_list = []
+ data_list: list = []
for project in iter(projects.values()):
for part in project:
part["file_index"] = len(data_list)
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index 2f8b28363b..628740ed32 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -167,6 +167,13 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_IMAGE_MASK);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGNMENT_TEXT_MASK);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XYZ);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, XZY);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YXZ);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, YZX);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZXY);
+ BIND_CORE_ENUM_CLASS_CONSTANT(EulerOrder, EULER_ORDER, ZYX);
+
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, NONE);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, SPECIAL);
BIND_CORE_ENUM_CLASS_CONSTANT(Key, KEY, ESCAPE);
@@ -588,8 +595,6 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXPRESSION);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PLACEHOLDER_TEXT);
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_OBJECT_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_TYPE_STRING);
@@ -646,6 +651,7 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFERRED_SET_RESOURCE);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_EDITOR_BASIC_SETTING);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_READ_ONLY);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_ARRAY);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_DEFAULT);
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index 23ee977df4..a2e3fab82c 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -39,89 +39,6 @@
#include "core/object/script_language.h"
#include "core/os/os.h"
-class RemoteDebugger::MultiplayerProfiler : public EngineProfiler {
- struct BandwidthFrame {
- uint32_t timestamp;
- int packet_size;
- };
-
- int bandwidth_in_ptr = 0;
- Vector<BandwidthFrame> bandwidth_in;
- int bandwidth_out_ptr = 0;
- Vector<BandwidthFrame> bandwidth_out;
- uint64_t last_bandwidth_time = 0;
-
- int bandwidth_usage(const Vector<BandwidthFrame> &p_buffer, int p_pointer) {
- ERR_FAIL_COND_V(p_buffer.size() == 0, 0);
- int total_bandwidth = 0;
-
- uint64_t timestamp = OS::get_singleton()->get_ticks_msec();
- uint64_t final_timestamp = timestamp - 1000;
-
- int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size();
-
- while (i != p_pointer && p_buffer[i].packet_size > 0) {
- if (p_buffer[i].timestamp < final_timestamp) {
- return total_bandwidth;
- }
- total_bandwidth += p_buffer[i].packet_size;
- i = (i + p_buffer.size() - 1) % p_buffer.size();
- }
-
- ERR_FAIL_COND_V_MSG(i == p_pointer, total_bandwidth, "Reached the end of the bandwidth profiler buffer, values might be inaccurate.");
- return total_bandwidth;
- }
-
-public:
- void toggle(bool p_enable, const Array &p_opts) {
- if (!p_enable) {
- bandwidth_in.clear();
- bandwidth_out.clear();
- } else {
- bandwidth_in_ptr = 0;
- bandwidth_in.resize(16384); // ~128kB
- for (int i = 0; i < bandwidth_in.size(); ++i) {
- bandwidth_in.write[i].packet_size = -1;
- }
- bandwidth_out_ptr = 0;
- bandwidth_out.resize(16384); // ~128kB
- for (int i = 0; i < bandwidth_out.size(); ++i) {
- bandwidth_out.write[i].packet_size = -1;
- }
- }
- }
-
- void add(const Array &p_data) {
- ERR_FAIL_COND(p_data.size() < 3);
- const String inout = p_data[0];
- int time = p_data[1];
- int size = p_data[2];
- if (inout == "in") {
- bandwidth_in.write[bandwidth_in_ptr].timestamp = time;
- bandwidth_in.write[bandwidth_in_ptr].packet_size = size;
- bandwidth_in_ptr = (bandwidth_in_ptr + 1) % bandwidth_in.size();
- } else if (inout == "out") {
- bandwidth_out.write[bandwidth_out_ptr].timestamp = time;
- bandwidth_out.write[bandwidth_out_ptr].packet_size = size;
- bandwidth_out_ptr = (bandwidth_out_ptr + 1) % bandwidth_out.size();
- }
- }
-
- void tick(double p_frame_time, double p_process_time, double p_physics_time, double p_physics_frame_time) {
- uint64_t pt = OS::get_singleton()->get_ticks_msec();
- if (pt - last_bandwidth_time > 200) {
- last_bandwidth_time = pt;
- int incoming_bandwidth = bandwidth_usage(bandwidth_in, bandwidth_in_ptr);
- int outgoing_bandwidth = bandwidth_usage(bandwidth_out, bandwidth_out_ptr);
-
- Array arr;
- arr.push_back(incoming_bandwidth);
- arr.push_back(outgoing_bandwidth);
- EngineDebugger::get_singleton()->send_message("multiplayer:bandwidth", arr);
- }
- }
-};
-
class RemoteDebugger::PerformanceProfiler : public EngineProfiler {
Object *performance = nullptr;
int last_perf_time = 0;
@@ -659,10 +576,6 @@ RemoteDebugger::RemoteDebugger(Ref<RemoteDebuggerPeer> p_peer) {
max_errors_per_second = GLOBAL_GET("network/limits/debugger/max_errors_per_second");
max_warnings_per_second = GLOBAL_GET("network/limits/debugger/max_warnings_per_second");
- // Multiplayer Profiler
- multiplayer_profiler.instantiate();
- multiplayer_profiler->bind("multiplayer");
-
// Performance Profiler
Object *perf = Engine::get_singleton()->get_singleton_object("Performance");
if (perf) {
diff --git a/core/debugger/remote_debugger.h b/core/debugger/remote_debugger.h
index fe4bbe86ea..944229d361 100644
--- a/core/debugger/remote_debugger.h
+++ b/core/debugger/remote_debugger.h
@@ -50,10 +50,8 @@ public:
private:
typedef DebuggerMarshalls::OutputError ErrorMessage;
- class MultiplayerProfiler;
class PerformanceProfiler;
- Ref<MultiplayerProfiler> multiplayer_profiler;
Ref<PerformanceProfiler> performance_profiler;
Ref<RemoteDebuggerPeer> peer;
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index e9362b4ea4..525362ec7c 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -79,10 +79,8 @@ RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) {
tcp_client = p_tcp;
if (tcp_client.is_valid()) { // Attaching to an already connected stream.
connected = true;
-#ifndef NO_THREADS
running = true;
thread.start(_thread_func, this);
-#endif
} else {
tcp_client.instantiate();
}
@@ -183,10 +181,8 @@ Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_po
return FAILED;
}
connected = true;
-#ifndef NO_THREADS
running = true;
thread.start(_thread_func, this);
-#endif
return OK;
}
@@ -208,9 +204,7 @@ void RemoteDebuggerPeerTCP::_thread_func(void *p_ud) {
}
void RemoteDebuggerPeerTCP::poll() {
-#ifdef NO_THREADS
- _poll();
-#endif
+ // Nothing to do, polling is done in thread.
}
void RemoteDebuggerPeerTCP::_poll() {
diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h
index 473fd8d712..2ab641d537 100644
--- a/core/debugger/remote_debugger_peer.h
+++ b/core/debugger/remote_debugger_peer.h
@@ -43,12 +43,12 @@ protected:
public:
virtual bool is_peer_connected() = 0;
+ virtual int get_max_message_size() const = 0;
virtual bool has_message() = 0;
virtual Error put_message(const Array &p_arr) = 0;
virtual Array get_message() = 0;
virtual void close() = 0;
virtual void poll() = 0;
- virtual int get_max_message_size() const = 0;
virtual bool can_block() const { return true; } // If blocking io is allowed on main thread (debug).
RemoteDebuggerPeer();
@@ -81,12 +81,12 @@ public:
Error connect_to_host(const String &p_host, uint16_t p_port);
- void poll() override;
bool is_peer_connected() override;
+ int get_max_message_size() const override;
bool has_message() override;
- Array get_message() override;
Error put_message(const Array &p_arr) override;
- int get_max_message_size() const override;
+ Array get_message() override;
+ void poll() override;
void close() override;
RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_stream = Ref<StreamPeerTCP>());
diff --git a/core/doc_data.h b/core/doc_data.h
index 3b7bf149b4..d5fbe37c96 100644
--- a/core/doc_data.h
+++ b/core/doc_data.h
@@ -32,7 +32,6 @@
#define DOC_DATA_H
#include "core/io/xml_parser.h"
-#include "core/templates/rb_map.h"
#include "core/variant/variant.h"
struct ScriptMemberInfo {
@@ -58,6 +57,27 @@ public:
}
return name < p_arg.name;
}
+ static ArgumentDoc from_dict(const Dictionary &p_dict) {
+ ArgumentDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ return doc;
+ }
};
struct MethodDoc {
@@ -98,6 +118,55 @@ public:
}
return name < p_method.name;
}
+ static MethodDoc from_dict(const Dictionary &p_dict) {
+ MethodDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("return_type")) {
+ doc.return_type = p_dict["return_type"];
+ }
+
+ if (p_dict.has("return_enum")) {
+ doc.return_enum = p_dict["return_enum"];
+ }
+
+ if (p_dict.has("qualifiers")) {
+ doc.qualifiers = p_dict["qualifiers"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ Array arguments;
+ if (p_dict.has("arguments")) {
+ arguments = p_dict["arguments"];
+ }
+ for (int i = 0; i < arguments.size(); i++) {
+ doc.arguments.push_back(ArgumentDoc::from_dict(arguments[i]));
+ }
+
+ Array errors_returned;
+ if (p_dict.has("errors_returned")) {
+ errors_returned = p_dict["errors_returned"];
+ }
+ for (int i = 0; i < errors_returned.size(); i++) {
+ doc.errors_returned.push_back(errors_returned[i]);
+ }
+
+ return doc;
+ }
};
struct ConstantDoc {
@@ -112,6 +181,43 @@ public:
bool operator<(const ConstantDoc &p_const) const {
return name < p_const.name;
}
+ static ConstantDoc from_dict(const Dictionary &p_dict) {
+ ConstantDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("value")) {
+ doc.value = p_dict["value"];
+ }
+
+ if (p_dict.has("is_value_valid")) {
+ doc.is_value_valid = p_dict["is_value_valid"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ return doc;
+ }
};
struct EnumDoc {
@@ -119,6 +225,31 @@ public:
bool is_bitfield = false;
String description;
Vector<DocData::ConstantDoc> values;
+ static EnumDoc from_dict(const Dictionary &p_dict) {
+ EnumDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("is_bitfield")) {
+ doc.is_bitfield = p_dict["is_bitfield"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ Array values;
+ if (p_dict.has("values")) {
+ values = p_dict["values"];
+ }
+ for (int i = 0; i < values.size(); i++) {
+ doc.values.push_back(ConstantDoc::from_dict(values[i]));
+ }
+
+ return doc;
+ }
};
struct PropertyDoc {
@@ -135,6 +266,55 @@ public:
bool operator<(const PropertyDoc &p_prop) const {
return name < p_prop.name;
}
+ static PropertyDoc from_dict(const Dictionary &p_dict) {
+ PropertyDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("enumeration")) {
+ doc.enumeration = p_dict["enumeration"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("setter")) {
+ doc.setter = p_dict["setter"];
+ }
+
+ if (p_dict.has("getter")) {
+ doc.getter = p_dict["getter"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ if (p_dict.has("overridden")) {
+ doc.overridden = p_dict["overridden"];
+ }
+
+ if (p_dict.has("overrides")) {
+ doc.overrides = p_dict["overrides"];
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ return doc;
+ }
};
struct ThemeItemDoc {
@@ -150,11 +330,49 @@ public:
}
return data_type < p_theme_item.data_type;
}
+ static ThemeItemDoc from_dict(const Dictionary &p_dict) {
+ ThemeItemDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("type")) {
+ doc.type = p_dict["type"];
+ }
+
+ if (p_dict.has("data_type")) {
+ doc.data_type = p_dict["data_type"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ if (p_dict.has("default_value")) {
+ doc.default_value = p_dict["default_value"];
+ }
+
+ return doc;
+ }
};
struct TutorialDoc {
String link;
String title;
+ static TutorialDoc from_dict(const Dictionary &p_dict) {
+ TutorialDoc doc;
+
+ if (p_dict.has("link")) {
+ doc.link = p_dict["link"];
+ }
+
+ if (p_dict.has("title")) {
+ doc.title = p_dict["title"];
+ }
+
+ return doc;
+ }
};
struct ClassDoc {
@@ -180,6 +398,127 @@ public:
bool operator<(const ClassDoc &p_class) const {
return name < p_class.name;
}
+ static ClassDoc from_dict(const Dictionary &p_dict) {
+ ClassDoc doc;
+
+ if (p_dict.has("name")) {
+ doc.name = p_dict["name"];
+ }
+
+ if (p_dict.has("inherits")) {
+ doc.inherits = p_dict["inherits"];
+ }
+
+ if (p_dict.has("category")) {
+ doc.category = p_dict["category"];
+ }
+
+ if (p_dict.has("brief_description")) {
+ doc.brief_description = p_dict["brief_description"];
+ }
+
+ if (p_dict.has("description")) {
+ doc.description = p_dict["description"];
+ }
+
+ Array tutorials;
+ if (p_dict.has("tutorials")) {
+ tutorials = p_dict["tutorials"];
+ }
+ for (int i = 0; i < tutorials.size(); i++) {
+ doc.tutorials.push_back(TutorialDoc::from_dict(tutorials[i]));
+ }
+
+ Array constructors;
+ if (p_dict.has("constructors")) {
+ constructors = p_dict["constructors"];
+ }
+ for (int i = 0; i < constructors.size(); i++) {
+ doc.constructors.push_back(MethodDoc::from_dict(constructors[i]));
+ }
+
+ Array methods;
+ if (p_dict.has("methods")) {
+ methods = p_dict["methods"];
+ }
+ for (int i = 0; i < methods.size(); i++) {
+ doc.methods.push_back(MethodDoc::from_dict(methods[i]));
+ }
+
+ Array operators;
+ if (p_dict.has("operators")) {
+ operators = p_dict["operators"];
+ }
+ for (int i = 0; i < operators.size(); i++) {
+ doc.operators.push_back(MethodDoc::from_dict(operators[i]));
+ }
+
+ Array signals;
+ if (p_dict.has("signals")) {
+ signals = p_dict["signals"];
+ }
+ for (int i = 0; i < signals.size(); i++) {
+ doc.signals.push_back(MethodDoc::from_dict(signals[i]));
+ }
+
+ Array constants;
+ if (p_dict.has("constants")) {
+ constants = p_dict["constants"];
+ }
+ for (int i = 0; i < constants.size(); i++) {
+ doc.constants.push_back(ConstantDoc::from_dict(constants[i]));
+ }
+
+ Dictionary enums;
+ if (p_dict.has("enums")) {
+ enums = p_dict["enums"];
+ }
+ for (int i = 0; i < enums.size(); i++) {
+ doc.enums[enums.get_key_at_index(i)] = enums.get_value_at_index(i);
+ }
+
+ Array properties;
+ if (p_dict.has("properties")) {
+ properties = p_dict["properties"];
+ }
+ for (int i = 0; i < properties.size(); i++) {
+ doc.properties.push_back(PropertyDoc::from_dict(properties[i]));
+ }
+
+ Array annotations;
+ if (p_dict.has("annotations")) {
+ annotations = p_dict["annotations"];
+ }
+ for (int i = 0; i < annotations.size(); i++) {
+ doc.annotations.push_back(MethodDoc::from_dict(annotations[i]));
+ }
+
+ Array theme_properties;
+ if (p_dict.has("theme_properties")) {
+ theme_properties = p_dict["theme_properties"];
+ }
+ for (int i = 0; i < theme_properties.size(); i++) {
+ doc.theme_properties.push_back(ThemeItemDoc::from_dict(theme_properties[i]));
+ }
+
+ if (p_dict.has("is_deprecated")) {
+ doc.is_deprecated = p_dict["is_deprecated"];
+ }
+
+ if (p_dict.has("is_experimental")) {
+ doc.is_experimental = p_dict["is_experimental"];
+ }
+
+ if (p_dict.has("is_script_doc")) {
+ doc.is_script_doc = p_dict["is_script_doc"];
+ }
+
+ if (p_dict.has("script_path")) {
+ doc.script_path = p_dict["script_path"];
+ }
+
+ return doc;
+ }
};
static void return_doc_from_retinfo(DocData::MethodDoc &p_method, const PropertyInfo &p_retinfo);
diff --git a/core/error/error_macros.h b/core/error/error_macros.h
index 2cfb5421c6..6901548cca 100644
--- a/core/error/error_macros.h
+++ b/core/error/error_macros.h
@@ -137,8 +137,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
@@ -173,8 +172,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures an integer index `m_index` is less than `m_size` and greater than or equal to 0.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_INDEX_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) < 0 || (m_index) >= (m_size))) { \
@@ -240,9 +238,9 @@ void _err_flush_stdout();
return; \
} else \
((void)0)
+
/**
- * Ensures an unsigned integer index `m_index` is less than `m_size`.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_UNSIGNED_INDEX_MSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_EDMSG(m_index, m_size, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
@@ -277,8 +275,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures an unsigned integer index `m_index` is less than `m_size`.
- * If not, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_UNSIGNED_INDEX_V_EDMSG` but also notifies the editor.
*/
#define ERR_FAIL_UNSIGNED_INDEX_V_EDMSG(m_index, m_size, m_retval, m_msg) \
if (unlikely((m_index) >= (m_size))) { \
@@ -346,8 +343,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures a pointer `m_param` is not null.
- * If it is null, prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_NULL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_EDMSG(m_param, m_msg) \
if (unlikely(m_param == nullptr)) { \
@@ -382,8 +378,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures a pointer `m_param` is not null.
- * If it is null, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_NULL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_NULL_V_EDMSG(m_param, m_retval, m_msg) \
if (unlikely(m_param == nullptr)) { \
@@ -423,11 +418,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current function returns.
- *
- * If checking for null use ERR_FAIL_NULL_MSG instead.
- * If checking index bounds use ERR_FAIL_INDEX_MSG instead.
+ * Same as `ERR_FAIL_COND_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
@@ -467,11 +458,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
- *
- * If checking for null use ERR_FAIL_NULL_V_MSG instead.
- * If checking index bounds use ERR_FAIL_INDEX_V_MSG instead.
+ * Same as `ERR_FAIL_COND_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_COND_V_EDMSG(m_cond, m_retval, m_msg) \
if (unlikely(m_cond)) { \
@@ -506,8 +493,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current loop continues.
+ * Same as `ERR_CONTINUE_MSG` but also notifies the editor.
*/
#define ERR_CONTINUE_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
@@ -542,8 +528,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Ensures `m_cond` is false.
- * If `m_cond` is true, prints `m_msg`, notifies in the editor, and the current loop breaks.
+ * Same as `ERR_BREAK_MSG` but also notifies the editor.
*/
#define ERR_BREAK_EDMSG(m_cond, m_msg) \
if (unlikely(m_cond)) { \
@@ -613,10 +598,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Try using `ERR_FAIL_COND_MSG`.
- * Only use this macro if more complex error detection or recovery is required.
- *
- * Prints `m_msg`, notifies in the editor, and the current function returns.
+ * Same as `ERR_FAIL_MSG` but also notifies the editor.
*/
#define ERR_FAIL_EDMSG(m_msg) \
if (true) { \
@@ -653,10 +635,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Try using `ERR_FAIL_COND_V_MSG`.
- * Only use this macro if more complex error detection or recovery is required.
- *
- * Prints `m_msg`, notifies in the editor, and the current function returns `m_retval`.
+ * Same as `ERR_FAIL_V_MSG` but also notifies the editor.
*/
#define ERR_FAIL_V_EDMSG(m_retval, m_msg) \
if (true) { \
@@ -666,7 +645,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG.
+ * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or `ERR_BREAK_MSG`.
* Only use this macro at the start of a function that has not been implemented yet, or
* if more complex error detection or recovery is required.
*
@@ -676,14 +655,10 @@ void _err_flush_stdout();
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg)
/**
- * Try using `ERR_FAIL_COND_MSG`, `ERR_FAIL_COND_V_MSG`, `ERR_CONTINUE_MSG` or ERR_BREAK_MSG.
- * Only use this macro at the start of a function that has not been implemented yet, or
- * if more complex error detection or recovery is required.
- *
- * Prints `m_msg` and notifies the editor.
+ * Same as `ERR_PRINT` but also notifies the editor.
*/
#define ERR_PRINT_ED(m_msg) \
- _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, )
+ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true)
/**
* Prints `m_msg` once during the application lifetime.
@@ -699,7 +674,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Prints `m_msg` and notifies the editor once during the application lifetime.
+ * Same as `ERR_PRINT_ONCE` but also notifies the editor.
*/
#define ERR_PRINT_ONCE_ED(m_msg) \
if (true) { \
@@ -722,9 +697,7 @@ void _err_flush_stdout();
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, false, ERR_HANDLER_WARNING)
/**
- * Prints `m_msg` and notifies the editor.
- *
- * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
+ * Same as `WARN_PRINT` but also notifies the editor.
*/
#define WARN_PRINT_ED(m_msg) \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, m_msg, true, ERR_HANDLER_WARNING)
@@ -745,9 +718,7 @@ void _err_flush_stdout();
((void)0)
/**
- * Prints `m_msg` and notifies the editor once during the application lifetime.
- *
- * If warning about deprecated usage, use `WARN_DEPRECATED` or `WARN_DEPRECATED_MSG` instead.
+ * Same as `WARN_PRINT_ONCE` but also notifies the editor.
*/
#define WARN_PRINT_ONCE_ED(m_msg) \
if (true) { \
diff --git a/core/extension/SCsub b/core/extension/SCsub
index 23727c1b76..a8f68a1533 100644
--- a/core/extension/SCsub
+++ b/core/extension/SCsub
@@ -3,10 +3,15 @@
Import("env")
import make_wrappers
+import make_interface_dumper
from platform_methods import run_in_subprocess
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", run_in_subprocess(make_wrappers.run))
-
+env.CommandNoCache(
+ "gdnative_interface_dump.gen.h",
+ ["gdnative_interface.h", "make_interface_dumper.py"],
+ run_in_subprocess(make_interface_dumper.run),
+)
env_extension = env.Clone()
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 5cf951a93c..a2c507e350 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "extension_api_dump.h"
+
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
@@ -38,7 +39,15 @@
#ifdef TOOLS_ENABLED
-static String get_type_name(const PropertyInfo &p_info) {
+static String get_builtin_or_variant_type_name(const Variant::Type p_type) {
+ if (p_type == Variant::NIL) {
+ return "Variant";
+ } else {
+ return Variant::get_type_name(p_type);
+ }
+}
+
+static String get_property_info_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::INT && (p_info.hint == PROPERTY_HINT_INT_IS_POINTER)) {
if (p_info.hint_string.is_empty()) {
return "void*";
@@ -46,6 +55,9 @@ static String get_type_name(const PropertyInfo &p_info) {
return p_info.hint_string + "*";
}
}
+ if (p_info.type == Variant::ARRAY && (p_info.hint == PROPERTY_HINT_ARRAY_TYPE)) {
+ return String("typedarray::") + p_info.hint_string;
+ }
if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM))) {
return String("enum::") + String(p_info.class_name);
}
@@ -67,7 +79,7 @@ static String get_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::NIL) {
return "void";
}
- return Variant::get_type_name(p_info.type);
+ return get_builtin_or_variant_type_name(p_info.type);
}
Dictionary NativeExtensionAPIDump::generate_extension_api() {
@@ -215,7 +227,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t);
Dictionary d2;
d2["name"] = name;
- uint32_t size;
+ uint32_t size = 0;
switch (i) {
case 0:
size = type_size_array[j].size_32_bits_real_float;
@@ -330,7 +342,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
last_type = t;
}
Dictionary d3;
- uint32_t offset;
+ uint32_t offset = 0;
switch (i) {
case 0:
offset = member_offset_array[idx].offset_32_bits_real_float;
@@ -427,8 +439,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary arg;
String argname = vararg ? "arg" + itos(i + 1) : Variant::get_utility_function_argument_name(name, i);
arg["name"] = argname;
- Variant::Type argtype = Variant::get_utility_function_argument_type(name, i);
- arg["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
+ arg["type"] = get_builtin_or_variant_type_name(Variant::get_utility_function_argument_type(name, i));
//no default value support in utility functions
arguments.push_back(arg);
}
@@ -458,11 +469,10 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d;
d["name"] = Variant::get_type_name(type);
if (Variant::has_indexing(type)) {
- Variant::Type index_type = Variant::get_indexed_element_type(type);
- d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type);
+ d["indexing_return_type"] = get_builtin_or_variant_type_name(Variant::get_indexed_element_type(type));
}
- d["is_keyed"] = Variant::ValidatedKeyedSetter(type);
+ d["is_keyed"] = Variant::is_keyed(type);
{
//members
@@ -473,7 +483,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (const StringName &member_name : member_names) {
Dictionary d2;
d2["name"] = String(member_name);
- d2["type"] = Variant::get_type_name(Variant::get_member_type(type, member_name));
+ d2["type"] = get_builtin_or_variant_type_name(Variant::get_member_type(type, member_name));
members.push_back(d2);
}
if (members.size()) {
@@ -490,7 +500,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = String(constant_name);
Variant constant = Variant::get_constant_value(type, constant_name);
- d2["type"] = Variant::get_type_name(constant.get_type());
+ d2["type"] = get_builtin_or_variant_type_name(constant.get_type());
d2["value"] = constant.get_construct_string();
constants.push_back(d2);
}
@@ -541,9 +551,9 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
Dictionary d2;
d2["name"] = Variant::get_operator_name(Variant::Operator(k));
if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) {
- d2["right_type"] = Variant::get_type_name(Variant::Type(j));
+ d2["right_type"] = get_builtin_or_variant_type_name(Variant::Type(j));
}
- d2["return_type"] = Variant::get_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
+ d2["return_type"] = get_builtin_or_variant_type_name(Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)));
operators.push_back(d2);
}
}
@@ -577,8 +587,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int j = 0; j < argcount; j++) {
Dictionary d3;
d3["name"] = Variant::get_builtin_method_argument_name(type, method_name, j);
- Variant::Type argtype = Variant::get_builtin_method_argument_type(type, method_name, j);
- d3["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype);
+ d3["type"] = get_builtin_or_variant_type_name(Variant::get_builtin_method_argument_type(type, method_name, j));
if (j >= (argcount - default_args.size())) {
int dargidx = j - (argcount - default_args.size());
@@ -610,7 +619,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int k = 0; k < argcount; k++) {
Dictionary d3;
d3["name"] = Variant::get_constructor_argument_name(type, j, k);
- d3["type"] = Variant::get_type_name(Variant::get_constructor_argument_type(type, j, k));
+ d3["type"] = get_builtin_or_variant_type_name(Variant::get_constructor_argument_type(type, j, k));
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -738,7 +747,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
d3["name"] = pinfo.name;
}
- d3["type"] = get_type_name(pinfo);
+ d3["type"] = get_property_info_type_name(pinfo);
if (i == -1) {
d2["return_value"] = d3;
@@ -781,7 +790,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
if (i >= 0) {
d3["name"] = pinfo.name;
}
- d3["type"] = get_type_name(pinfo);
+ d3["type"] = get_property_info_type_name(pinfo);
if (method->get_argument_meta(i) > 0) {
static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" };
@@ -828,7 +837,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
for (int i = 0; i < F.arguments.size(); i++) {
Dictionary d3;
d3["name"] = F.arguments[i].name;
- d3["type"] = get_type_name(F.arguments[i]);
+ d3["type"] = get_property_info_type_name(F.arguments[i]);
arguments.push_back(d3);
}
if (arguments.size()) {
@@ -860,7 +869,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
StringName property_name = F.name;
Dictionary d2;
- d2["type"] = get_type_name(F);
+ d2["type"] = get_property_info_type_name(F);
d2["name"] = String(property_name);
d2["setter"] = ClassDB::get_property_setter(class_name, F.name);
d2["getter"] = ClassDB::get_property_getter(class_name, F.name);
@@ -930,9 +939,9 @@ void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path)
Ref<JSON> json;
json.instantiate();
- String text = json->stringify(api, "\t", false);
+ String text = json->stringify(api, "\t", false) + "\n";
Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
- CharString cs = text.ascii();
- fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
+ fa->store_string(text);
}
-#endif
+
+#endif // TOOLS_ENABLED
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 6c680e82c9..864f2fa86b 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -61,8 +61,9 @@ static void gdnative_print_script_error(const char *p_description, const char *p
_err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
}
-uint64_t gdnative_get_native_struct_size(const char *p_name) {
- return ClassDB::get_native_struct_size(p_name);
+uint64_t gdnative_get_native_struct_size(const GDNativeStringNamePtr p_name) {
+ const StringName name = *reinterpret_cast<const StringName *>(p_name);
+ return ClassDB::get_native_struct_size(name);
}
// Variant functions
@@ -81,11 +82,11 @@ static void gdnative_variant_destroy(GDNativeVariantPtr p_self) {
static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
Variant *self = (Variant *)p_self;
- const StringName *method = (const StringName *)p_method;
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
- self->callp(*method, args, p_argcount, ret, error);
+ self->callp(method, args, p_argcount, ret, error);
memnew_placement(r_return, Variant(ret));
if (r_error) {
@@ -97,11 +98,11 @@ static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStrin
static void gdnative_variant_call_static(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
Variant::Type type = (Variant::Type)p_type;
- const StringName *method = (const StringName *)p_method;
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
const Variant **args = (const Variant **)p_args;
Variant ret;
Callable::CallError error;
- Variant::call_static(type, *method, args, p_argcount, ret, error);
+ Variant::call_static(type, method, args, p_argcount, ret, error);
memnew_placement(r_return, Variant(ret));
if (r_error) {
@@ -469,11 +470,11 @@ static GDNativeTypeFromVariantConstructorFunc gdnative_get_type_from_variant_con
static GDNativePtrOperatorEvaluator gdnative_variant_get_ptr_operator_evaluator(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b) {
return (GDNativePtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b));
}
-static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash) {
- StringName method = p_method;
+static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, GDNativeInt p_hash) {
+ const StringName method = *reinterpret_cast<const StringName *>(p_method);
uint32_t hash = Variant::get_builtin_method_hash(Variant::Type(p_type), method);
if (hash != p_hash) {
- ERR_PRINT_ONCE("Error getting method " + String(method) + ", hash mismatch.");
+ ERR_PRINT_ONCE("Error getting method " + method + ", hash mismatch.");
return nullptr;
}
@@ -497,11 +498,13 @@ static void gdnative_variant_construct(GDNativeVariantType p_type, GDNativeVaria
r_error->expected = error.expected;
}
}
-static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const char *p_member) {
- return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), p_member);
+static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) {
+ const StringName member = *reinterpret_cast<const StringName *>(p_member);
+ return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), member);
}
-static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const char *p_member) {
- return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), p_member);
+static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) {
+ const StringName member = *reinterpret_cast<const StringName *>(p_member);
+ return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), member);
}
static GDNativePtrIndexedSetter gdnative_variant_get_ptr_indexed_setter(GDNativeVariantType p_type) {
return (GDNativePtrIndexedSetter)Variant::get_member_ptr_indexed_setter(Variant::Type(p_type));
@@ -518,14 +521,15 @@ static GDNativePtrKeyedGetter gdnative_variant_get_ptr_keyed_getter(GDNativeVari
static GDNativePtrKeyedChecker gdnative_variant_get_ptr_keyed_checker(GDNativeVariantType p_type) {
return (GDNativePtrKeyedChecker)Variant::get_member_ptr_keyed_checker(Variant::Type(p_type));
}
-static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret) {
- memnew_placement(r_ret, Variant(Variant::get_constant_value(Variant::Type(p_type), p_constant)));
+static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const GDNativeStringNamePtr p_constant, GDNativeVariantPtr r_ret) {
+ StringName constant = *reinterpret_cast<const StringName *>(p_constant);
+ memnew_placement(r_ret, Variant(Variant::get_constant_value(Variant::Type(p_type), constant)));
}
-static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const char *p_function, GDNativeInt p_hash) {
- StringName function = p_function;
+static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const GDNativeStringNamePtr p_function, GDNativeInt p_hash) {
+ StringName function = *reinterpret_cast<const StringName *>(p_function);
uint32_t hash = Variant::get_utility_function_hash(function);
if (hash != p_hash) {
- ERR_PRINT_ONCE("Error getting utility function " + String(function) + ", hash mismatch.");
+ ERR_PRINT_ONCE("Error getting utility function " + function + ", hash mismatch.");
return nullptr;
}
return (GDNativePtrUtilityFunction)Variant::get_ptr_utility_function(function);
@@ -559,7 +563,7 @@ static void gdnative_string_new_with_utf32_chars(GDNativeStringPtr r_dest, const
static void gdnative_string_new_with_wide_chars(GDNativeStringPtr r_dest, const wchar_t *p_contents) {
String *dest = (String *)r_dest;
- if (sizeof(wchar_t) == 2) {
+ if constexpr (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse.
memnew_placement(dest, String);
dest->parse_utf16((const char16_t *)p_contents);
@@ -596,7 +600,7 @@ static void gdnative_string_new_with_utf32_chars_and_len(GDNativeStringPtr r_des
static void gdnative_string_new_with_wide_chars_and_len(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size) {
String *dest = (String *)r_dest;
- if (sizeof(wchar_t) == 2) {
+ if constexpr (sizeof(wchar_t) == 2) {
// wchar_t is 16 bit, parse.
memnew_placement(dest, String);
dest->parse_utf16((const char16_t *)p_contents, p_size);
@@ -655,7 +659,7 @@ static GDNativeInt gdnative_string_to_utf32_chars(const GDNativeStringPtr p_self
return len;
}
static GDNativeInt gdnative_string_to_wide_chars(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length) {
- if (sizeof(wchar_t) == 4) {
+ if constexpr (sizeof(wchar_t) == 4) {
return gdnative_string_to_utf32_chars(p_self, (char32_t *)r_text, p_max_write_length);
} else {
return gdnative_string_to_utf16_chars(p_self, (char16_t *)r_text, p_max_write_length);
@@ -836,8 +840,9 @@ static void gdnative_object_destroy(GDNativeObjectPtr p_o) {
memdelete((Object *)p_o);
}
-static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
- return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
+static GDNativeObjectPtr gdnative_global_get_singleton(const GDNativeStringNamePtr p_name) {
+ const StringName name = *reinterpret_cast<const StringName *>(p_name);
+ return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(name);
}
static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_object, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) {
@@ -850,9 +855,10 @@ static void gdnative_object_set_instance_binding(GDNativeObjectPtr p_object, voi
o->set_instance_binding(p_token, p_binding, p_callbacks);
}
-static void gdnative_object_set_instance(GDNativeObjectPtr p_object, const char *p_classname, GDExtensionClassInstancePtr p_instance) {
+static void gdnative_object_set_instance(GDNativeObjectPtr p_object, const GDNativeStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
Object *o = (Object *)p_object;
- ClassDB::set_object_extension_instance(o, p_classname, p_instance);
+ ClassDB::set_object_extension_instance(o, classname, p_instance);
}
static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
@@ -880,23 +886,26 @@ static GDNativeScriptInstancePtr gdnative_script_instance_create(const GDNativeE
return reinterpret_cast<GDNativeScriptInstancePtr>(script_instance_extension);
}
-static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_classname, const char *p_methodname, GDNativeInt p_hash) {
- MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname));
+static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const GDNativeStringNamePtr p_classname, const GDNativeStringNamePtr p_methodname, GDNativeInt p_hash) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ const StringName methodname = *reinterpret_cast<const StringName *>(p_methodname);
+ MethodBind *mb = ClassDB::get_method(classname, methodname);
ERR_FAIL_COND_V(!mb, nullptr);
if (mb->get_hash() != p_hash) {
- ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'.");
+ ERR_PRINT("Hash mismatch for method '" + classname + "." + methodname + "'.");
return nullptr;
}
- // MethodBind *mb = ClassDB::get_method("Node", "get_name");
return (GDNativeMethodBindPtr)mb;
}
-static GDNativeObjectPtr gdnative_classdb_construct_object(const char *p_classname) {
- return (GDNativeObjectPtr)ClassDB::instantiate(p_classname);
+static GDNativeObjectPtr gdnative_classdb_construct_object(const GDNativeStringNamePtr p_classname) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ return (GDNativeObjectPtr)ClassDB::instantiate(classname);
}
-static void *gdnative_classdb_get_class_tag(const char *p_classname) {
- ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(p_classname);
+static void *gdnative_classdb_get_class_tag(const GDNativeStringNamePtr p_classname) {
+ const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(classname);
return class_info ? class_info->class_ptr : nullptr;
}
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 39378d8261..a361e40096 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -201,22 +201,22 @@ typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_
typedef uint64_t (*GDNativeExtensionClassGetRID)(GDExtensionClassInstancePtr p_instance);
typedef struct {
- uint32_t type;
- const char *name;
- const char *class_name;
- uint32_t hint;
- const char *hint_string;
- uint32_t usage;
+ GDNativeVariantType type;
+ GDNativeStringNamePtr name;
+ GDNativeStringNamePtr class_name;
+ uint32_t hint; // Bitfield of `PropertyHint` (defined in `extension_api.json`)
+ GDNativeStringPtr hint_string;
+ uint32_t usage; // Bitfield of `PropertyUsageFlags` (defined in `extension_api.json`)
} GDNativePropertyInfo;
typedef struct {
- const char *name;
+ GDNativeStringNamePtr name;
GDNativePropertyInfo return_value;
- uint32_t flags; // From GDNativeExtensionClassMethodFlags
+ uint32_t flags; // Bitfield of `GDNativeExtensionClassMethodFlags`
int32_t id;
- GDNativePropertyInfo *arguments;
+ GDNativePropertyInfo *arguments; // array of `argument_count` size
uint32_t argument_count;
- GDNativeVariantPtr default_arguments;
+ GDNativeVariantPtr *default_arguments; // array of `default_argument_count` size
uint32_t default_argument_count;
} GDNativeMethodInfo;
@@ -225,16 +225,17 @@ typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstanceP
typedef GDNativeBool (*GDNativeExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name);
typedef GDNativeBool (*GDNativeExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
-typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr p_out);
+typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr p_out);
typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
typedef GDNativeObjectPtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata);
typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
-typedef void (*GDNativeExtensionClassObjectInstance)(GDExtensionClassInstancePtr p_instance, GDNativeObjectPtr p_object_instance);
-typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name);
+typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const GDNativeStringNamePtr p_name);
typedef struct {
+ GDNativeBool is_virtual;
+ GDNativeBool is_abstract;
GDNativeExtensionClassSet set_func;
GDNativeExtensionClassGet get_func;
GDNativeExtensionClassGetPropertyList get_property_list_func;
@@ -283,24 +284,21 @@ typedef enum {
typedef void (*GDNativeExtensionClassMethodCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
typedef void (*GDNativeExtensionClassMethodPtrCall)(void *method_userdata, GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
-/* passing -1 as argument in the following functions refers to the return type */
-typedef GDNativeVariantType (*GDNativeExtensionClassMethodGetArgumentType)(void *p_method_userdata, int32_t p_argument);
-typedef void (*GDNativeExtensionClassMethodGetArgumentInfo)(void *p_method_userdata, int32_t p_argument, GDNativePropertyInfo *r_info);
-typedef GDNativeExtensionClassMethodArgumentMetadata (*GDNativeExtensionClassMethodGetArgumentMetadata)(void *p_method_userdata, int32_t p_argument);
-
typedef struct {
- const char *name;
+ GDNativeStringNamePtr name;
void *method_userdata;
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
- uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */
+ uint32_t method_flags; // Bitfield of `GDNativeExtensionClassMethodFlags`
uint32_t argument_count;
GDNativeBool has_return_value;
- GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
- GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
- GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
+ GDNativePropertyInfo *return_value_info; // Ignored if `has_return_value` is false
+ GDNativeExtensionClassMethodArgumentMetadata return_value_metadata; // Ignored if `has_return_value` is false
+ /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */
+ GDNativePropertyInfo *aguments_info; // array of `argument_count` size
+ GDNativeExtensionClassMethodArgumentMetadata *aguments_metadata; // array of `argument_count` size
uint32_t default_argument_count;
- GDNativeVariantPtr *default_arguments;
+ GDNativeVariantPtr *default_arguments; // array of `default_argument_count` size
} GDNativeExtensionClassMethodInfo;
/* SCRIPT INSTANCE EXTENSION */
@@ -327,7 +325,7 @@ typedef GDNativeBool (*GDNativeExtensionScriptInstanceHasMethod)(GDNativeExtensi
typedef void (*GDNativeExtensionScriptInstanceCall)(GDNativeExtensionScriptInstanceDataPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error);
typedef void (*GDNativeExtensionScriptInstanceNotification)(GDNativeExtensionScriptInstanceDataPtr p_instance, int32_t p_what);
-typedef const char *(*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid);
+typedef void (*GDNativeExtensionScriptInstanceToString)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeBool *r_is_valid, GDNativeStringPtr r_out);
typedef void (*GDNativeExtensionScriptInstanceRefCountIncremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef GDNativeBool (*GDNativeExtensionScriptInstanceRefCountDecremented)(GDNativeExtensionScriptInstanceDataPtr p_instance);
@@ -348,7 +346,6 @@ typedef struct {
GDNativeExtensionScriptInstanceGet get_func;
GDNativeExtensionScriptInstanceGetPropertyList get_property_list_func;
GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
- GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
GDNativeExtensionScriptInstancePropertyCanRevert property_can_revert_func;
GDNativeExtensionScriptInstancePropertyGetRevert property_get_revert_func;
@@ -358,6 +355,7 @@ typedef struct {
GDNativeExtensionScriptInstanceGetMethodList get_method_list_func;
GDNativeExtensionScriptInstanceFreeMethodList free_method_list_func;
+ GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
GDNativeExtensionScriptInstanceHasMethod has_method_func;
@@ -399,7 +397,7 @@ typedef struct {
void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line);
- uint64_t (*get_native_struct_size)(const char *p_name);
+ uint64_t (*get_native_struct_size)(const GDNativeStringNamePtr p_name);
/* GODOT VARIANT */
@@ -442,19 +440,19 @@ typedef struct {
GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type);
GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type);
GDNativePtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b);
- GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash);
+ GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, GDNativeInt p_hash);
GDNativePtrConstructor (*variant_get_ptr_constructor)(GDNativeVariantType p_type, int32_t p_constructor);
GDNativePtrDestructor (*variant_get_ptr_destructor)(GDNativeVariantType p_type);
void (*variant_construct)(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error);
- GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const char *p_member);
- GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const char *p_member);
+ GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member);
+ GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member);
GDNativePtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDNativeVariantType p_type);
GDNativePtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDNativeVariantType p_type);
GDNativePtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDNativeVariantType p_type);
GDNativePtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDNativeVariantType p_type);
GDNativePtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDNativeVariantType p_type);
- void (*variant_get_constant_value)(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret);
- GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const char *p_function, GDNativeInt p_hash);
+ void (*variant_get_constant_value)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_constant, GDNativeVariantPtr r_ret);
+ GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const GDNativeStringNamePtr p_function, GDNativeInt p_hash);
/* extra utilities */
@@ -523,12 +521,12 @@ typedef struct {
void (*object_method_bind_call)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeVariantPtr *p_args, GDNativeInt p_arg_count, GDNativeVariantPtr r_ret, GDNativeCallError *r_error);
void (*object_method_bind_ptrcall)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
void (*object_destroy)(GDNativeObjectPtr p_o);
- GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
+ GDNativeObjectPtr (*global_get_singleton)(const GDNativeStringNamePtr p_name);
void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks);
void (*object_set_instance_binding)(GDNativeObjectPtr p_o, void *p_token, void *p_binding, const GDNativeInstanceBindingCallbacks *p_callbacks);
- void (*object_set_instance)(GDNativeObjectPtr p_o, const char *p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
+ void (*object_set_instance)(GDNativeObjectPtr p_o, const GDNativeStringNamePtr p_classname, GDExtensionClassInstancePtr p_instance); /* p_classname should be a registered extension class and should extend the p_o object's class. */
GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
@@ -539,20 +537,21 @@ typedef struct {
GDNativeScriptInstancePtr (*script_instance_create)(const GDNativeExtensionScriptInstanceInfo *p_info, GDNativeExtensionScriptInstanceDataPtr p_instance_data);
/* CLASSDB */
- GDNativeObjectPtr (*classdb_construct_object)(const char *p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
- GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash);
- void *(*classdb_get_class_tag)(const char *p_classname);
+ GDNativeObjectPtr (*classdb_construct_object)(const GDNativeStringNamePtr p_classname); /* The passed class must be a built-in godot class, or an already-registered extension class. In both case, object_set_instance should be called to fully initialize the object. */
+ GDNativeMethodBindPtr (*classdb_get_method_bind)(const GDNativeStringNamePtr p_classname, const GDNativeStringNamePtr p_methodname, GDNativeInt p_hash);
+ void *(*classdb_get_class_tag)(const GDNativeStringNamePtr p_classname);
/* CLASSDB EXTENSION */
- void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
- void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
- void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
- void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
- void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
- void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
- void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
- void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
+ // Provided parameters for `classdb_register_extension_*` can be safely freed once the function returns
+ void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
+ void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
+ void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
+ void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativePropertyInfo *p_info, const GDNativeStringNamePtr p_setter, const GDNativeStringNamePtr p_getter);
+ void (*classdb_register_extension_class_property_group)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_group_name, const GDNativeStringPtr p_prefix);
+ void (*classdb_register_extension_class_property_subgroup)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_subgroup_name, const GDNativeStringPtr p_prefix);
+ void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
+ void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */
void (*get_library_path)(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
diff --git a/core/extension/make_interface_dumper.py b/core/extension/make_interface_dumper.py
new file mode 100644
index 0000000000..cc85c728d5
--- /dev/null
+++ b/core/extension/make_interface_dumper.py
@@ -0,0 +1,47 @@
+def run(target, source, env):
+ src = source[0]
+ dst = target[0]
+ f = open(src, "r", encoding="utf-8")
+ g = open(dst, "w", encoding="utf-8")
+
+ g.write(
+ """/* THIS FILE IS GENERATED DO NOT EDIT */
+#ifndef GDNATIVE_INTERFACE_DUMP_H
+#define GDNATIVE_INTERFACE_DUMP_H
+
+#ifdef TOOLS_ENABLED
+
+#include "core/io/file_access.h"
+#include "core/string/ustring.h"
+
+class GDNativeInterfaceDump {
+ private:
+ static constexpr char const *gdnative_interface_dump ="""
+ )
+ for line in f:
+ g.write('"' + line.rstrip().replace('"', '\\"') + '\\n"\n')
+ g.write(";\n")
+
+ g.write(
+ """
+ public:
+ static void generate_gdnative_interface_file(const String &p_path) {
+ Ref<FileAccess> fa = FileAccess::open(p_path, FileAccess::WRITE);
+ CharString cs(gdnative_interface_dump);
+ fa->store_buffer((const uint8_t *)cs.ptr(), cs.length());
+ };
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // GDNATIVE_INTERFACE_DUMP_H
+"""
+ )
+ g.close()
+ f.close()
+
+
+if __name__ == "__main__":
+ from platform_methods import subprocess_main
+
+ subprocess_main(globals())
diff --git a/core/extension/make_wrappers.py b/core/extension/make_wrappers.py
index 862d313fba..1e4634ad2c 100644
--- a/core/extension/make_wrappers.py
+++ b/core/extension/make_wrappers.py
@@ -1,4 +1,60 @@
-proto = """
+proto_mod = """
+#define MODBIND$VER($RETTYPE m_name$ARG) \\
+virtual $RETVAL _##m_name($FUNCARGS) $CONST; \\
+_FORCE_INLINE_ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
+ $RETX _##m_name($CALLARGS);\\
+}
+"""
+
+
+def generate_mod_version(argcount, const=False, returns=False):
+ s = proto_mod
+ sproto = str(argcount)
+ method_info = ""
+ if returns:
+ sproto += "R"
+ s = s.replace("$RETTYPE", "m_ret, ")
+ s = s.replace("$RETVAL", "m_ret")
+ s = s.replace("$RETX", "return")
+
+ else:
+ s = s.replace("$RETTYPE", "")
+ s = s.replace("$RETVAL", "void")
+ s = s.replace("$RETX", "")
+
+ if const:
+ sproto += "C"
+ s = s.replace("$CONST", "const")
+ else:
+ s = s.replace("$CONST", "")
+
+ s = s.replace("$VER", sproto)
+ argtext = ""
+ funcargs = ""
+ callargs = ""
+
+ for i in range(argcount):
+ if i > 0:
+ funcargs += ", "
+ callargs += ", "
+
+ argtext += ", m_type" + str(i + 1)
+ funcargs += "m_type" + str(i + 1) + " arg" + str(i + 1)
+ callargs += "arg" + str(i + 1)
+
+ if argcount:
+ s = s.replace("$ARG", argtext)
+ s = s.replace("$FUNCARGS", funcargs)
+ s = s.replace("$CALLARGS", callargs)
+ else:
+ s = s.replace("$ARG", "")
+ s = s.replace("$FUNCARGS", funcargs)
+ s = s.replace("$CALLARGS", callargs)
+
+ return s
+
+
+proto_ex = """
#define EXBIND$VER($RETTYPE m_name$ARG) \\
GDVIRTUAL$VER($RETTYPE_##m_name$ARG)\\
virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
@@ -9,8 +65,8 @@ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
"""
-def generate_version(argcount, const=False, returns=False):
- s = proto
+def generate_ex_version(argcount, const=False, returns=False):
+ s = proto_ex
sproto = str(argcount)
method_info = ""
if returns:
@@ -63,25 +119,28 @@ def generate_version(argcount, const=False, returns=False):
def run(target, source, env):
-
max_versions = 12
txt = """
#ifndef GDEXTENSION_WRAPPERS_GEN_H
#define GDEXTENSION_WRAPPERS_GEN_H
-
-
"""
for i in range(max_versions + 1):
+ txt += "\n/* Extension Wrapper " + str(i) + " Arguments */\n"
+ txt += generate_ex_version(i, False, False)
+ txt += generate_ex_version(i, False, True)
+ txt += generate_ex_version(i, True, False)
+ txt += generate_ex_version(i, True, True)
- txt += "/* " + str(i) + " Arguments */\n\n"
- txt += generate_version(i, False, False)
- txt += generate_version(i, False, True)
- txt += generate_version(i, True, False)
- txt += generate_version(i, True, True)
+ for i in range(max_versions + 1):
+ txt += "\n/* Module Wrapper " + str(i) + " Arguments */\n"
+ txt += generate_mod_version(i, False, False)
+ txt += generate_mod_version(i, False, True)
+ txt += generate_mod_version(i, True, False)
+ txt += generate_mod_version(i, True, True)
- txt += "#endif"
+ txt += "\n#endif\n"
with open(target[0], "w") as f:
f.write(txt)
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index 6418da2235..8bbb72fd82 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -42,26 +42,37 @@ String NativeExtension::get_extension_list_config_file() {
class NativeExtensionMethodBind : public MethodBind {
GDNativeExtensionClassMethodCall call_func;
GDNativeExtensionClassMethodPtrCall ptrcall_func;
- GDNativeExtensionClassMethodGetArgumentType get_argument_type_func;
- GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func;
- GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func;
void *method_userdata;
bool vararg;
+ PropertyInfo return_value_info;
+ GodotTypeInfo::Metadata return_value_metadata;
+ List<PropertyInfo> arguments_info;
+ List<GodotTypeInfo::Metadata> arguments_metadata;
protected:
virtual Variant::Type _gen_argument_type(int p_arg) const override {
- return Variant::Type(get_argument_type_func(method_userdata, p_arg));
+ if (p_arg < 0) {
+ return return_value_info.type;
+ } else {
+ return arguments_info[p_arg].type;
+ }
}
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
- GDNativePropertyInfo pinfo;
- get_argument_info_func(method_userdata, p_arg, &pinfo);
- return PropertyInfo(pinfo);
+ if (p_arg < 0) {
+ return return_value_info;
+ } else {
+ return arguments_info[p_arg];
+ }
}
public:
#ifdef DEBUG_METHODS_ENABLED
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const override {
- return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg));
+ if (p_arg < 0) {
+ return return_value_metadata;
+ } else {
+ return arguments_metadata[p_arg];
+ }
}
#endif
@@ -89,10 +100,17 @@ public:
method_userdata = p_method_info->method_userdata;
call_func = p_method_info->call_func;
ptrcall_func = p_method_info->ptrcall_func;
- get_argument_type_func = p_method_info->get_argument_type_func;
- get_argument_info_func = p_method_info->get_argument_info_func;
- get_argument_metadata_func = p_method_info->get_argument_metadata_func;
- set_name(p_method_info->name);
+ set_name(*reinterpret_cast<StringName *>(p_method_info->name));
+
+ if (p_method_info->has_return_value) {
+ return_value_info = PropertyInfo(*p_method_info->return_value_info);
+ return_value_metadata = GodotTypeInfo::Metadata(p_method_info->return_value_metadata);
+ }
+
+ for (uint32_t i = 0; i < p_method_info->argument_count; i++) {
+ arguments_info.push_back(PropertyInfo(p_method_info->aguments_info[i]));
+ arguments_metadata.push_back(GodotTypeInfo::Metadata(p_method_info->aguments_metadata[i]));
+ }
set_hint_flags(p_method_info->method_flags);
@@ -117,15 +135,15 @@ public:
static GDNativeInterface gdnative_interface;
-void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
+void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
+ StringName class_name = *reinterpret_cast<StringName *>(p_class_name);
+ StringName parent_class_name = *reinterpret_cast<StringName *>(p_parent_class_name);
ERR_FAIL_COND_MSG(!String(class_name).is_valid_identifier(), "Attempt to register extension class '" + class_name + "', which is not a valid class identifier.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered.");
Extension *parent_extension = nullptr;
- StringName parent_class_name = p_parent_class_name;
if (self->extension_classes.has(parent_class_name)) {
parent_extension = &self->extension_classes[parent_class_name];
@@ -152,6 +170,8 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.parent_class_name = parent_class_name;
extension->native_extension.class_name = class_name;
extension->native_extension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
+ extension->native_extension.is_virtual = p_extension_funcs->is_virtual;
+ extension->native_extension.is_abstract = p_extension_funcs->is_abstract;
extension->native_extension.set = p_extension_funcs->set_func;
extension->native_extension.get = p_extension_funcs->get_func;
extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func;
@@ -170,11 +190,11 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
ClassDB::register_extension_class(&extension->native_extension);
}
-void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
+void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- StringName method_name = p_method_info->name;
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName method_name = *reinterpret_cast<const StringName *>(p_method_info->name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
@@ -184,56 +204,63 @@ void NativeExtension::_register_extension_class_method(const GDNativeExtensionCl
ClassDB::bind_method_custom(class_name, method);
}
-void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield) {
+void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'.");
-
- //Extension *extension = &self->extension_classes[class_name];
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName enum_name = *reinterpret_cast<const StringName *>(p_enum_name);
+ StringName constant_name = *reinterpret_cast<const StringName *>(p_constant_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension constant '" + constant_name + "' for unexisting class '" + class_name + "'.");
- ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value, p_is_bitfield);
+ ClassDB::bind_integer_constant(class_name, enum_name, constant_name, p_constant_value, p_is_bitfield);
}
-void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter) {
+void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativePropertyInfo *p_info, const GDNativeStringNamePtr p_setter, const GDNativeStringNamePtr p_getter) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- String property_name = p_info->name;
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName setter = *reinterpret_cast<const StringName *>(p_setter);
+ StringName getter = *reinterpret_cast<const StringName *>(p_getter);
+ String property_name = *reinterpret_cast<const StringName *>(p_info->name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'.");
//Extension *extension = &self->extension_classes[class_name];
PropertyInfo pinfo(*p_info);
- ClassDB::add_property(class_name, pinfo, p_setter, p_getter);
+ ClassDB::add_property(class_name, pinfo, setter, getter);
}
-void NativeExtension::_register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix) {
+void NativeExtension::_register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_group_name, const GDNativeStringPtr p_prefix) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + String(p_group_name) + "' for unexisting class '" + class_name + "'.");
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ String group_name = *reinterpret_cast<const String *>(p_group_name);
+ String prefix = *reinterpret_cast<const String *>(p_prefix);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property group '" + group_name + "' for unexisting class '" + class_name + "'.");
- ClassDB::add_property_group(class_name, p_group_name, p_prefix);
+ ClassDB::add_property_group(class_name, group_name, prefix);
}
-void NativeExtension::_register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix) {
+void NativeExtension::_register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringPtr p_subgroup_name, const GDNativeStringPtr p_prefix) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + String(p_subgroup_name) + "' for unexisting class '" + class_name + "'.");
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ String subgroup_name = *reinterpret_cast<const String *>(p_subgroup_name);
+ String prefix = *reinterpret_cast<const String *>(p_prefix);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property subgroup '" + subgroup_name + "' for unexisting class '" + class_name + "'.");
- ClassDB::add_property_subgroup(class_name, p_subgroup_name, p_prefix);
+ ClassDB::add_property_subgroup(class_name, subgroup_name, prefix);
}
-void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
+void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
- ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'.");
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
+ StringName signal_name = *reinterpret_cast<const StringName *>(p_signal_name);
+ ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class signal '" + signal_name + "' for unexisting class '" + class_name + "'.");
MethodInfo s;
- s.name = p_signal_name;
+ s.name = signal_name;
for (int i = 0; i < p_argument_count; i++) {
PropertyInfo arg(p_argument_info[i]);
s.arguments.push_back(arg);
@@ -241,10 +268,10 @@ void NativeExtension::_register_extension_class_signal(const GDNativeExtensionCl
ClassDB::add_signal(class_name, s);
}
-void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name) {
+void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name) {
NativeExtension *self = static_cast<NativeExtension *>(p_library);
- StringName class_name = p_class_name;
+ StringName class_name = *reinterpret_cast<const StringName *>(p_class_name);
ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'.");
Extension *ext = &self->extension_classes[class_name];
ERR_FAIL_COND_MSG(ext->native_extension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it.");
diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h
index b7238d2899..70f6f9f039 100644
--- a/core/extension/native_extension.h
+++ b/core/extension/native_extension.h
@@ -47,14 +47,14 @@ class NativeExtension : public Resource {
HashMap<StringName, Extension> extension_classes;
- static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
- static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
- static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
- static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter);
- static void _register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_group_name, const char *p_prefix);
- static void _register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_subgroup_name, const char *p_prefix);
- static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
- static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name);
+ static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs);
+ static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info);
+ static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_enum_name, const GDNativeStringNamePtr p_constant_name, GDNativeInt p_constant_value, GDNativeBool p_is_bitfield);
+ static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativePropertyInfo *p_info, const GDNativeStringNamePtr p_setter, const GDNativeStringNamePtr p_getter);
+ static void _register_extension_class_property_group(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_group_name, const GDNativeStringNamePtr p_prefix);
+ static void _register_extension_class_property_subgroup(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_subgroup_name, const GDNativeStringNamePtr p_prefix);
+ static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name, const GDNativeStringNamePtr p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count);
+ static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const GDNativeStringNamePtr p_class_name);
static void _get_library_path(const GDNativeExtensionClassLibraryPtr p_library, GDNativeStringPtr r_path);
GDNativeInitialization initialization;
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index 5ae3b2c799..774d1be6b5 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -21,6 +21,7 @@
03000000c82d00000090000000000000,8BitDo FC30 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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001251000000000000,8BitDo Lite 2,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001151000000000000,8BitDo Lite SE,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -68,6 +69,7 @@
03000000c82d00000121000000000000,8BitDo SN30 Pro for Android,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,
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,
+03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,paddle1:b23,paddle2:b19,platform:Windows,
03000000a00500003232000000000000,8BitDo Zero,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,
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,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,
@@ -367,6 +369,7 @@
030000002a0600001024000000000000,Matricom,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:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows,
030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows,
+03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,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:Windows,
03000000790000003018000000000000,Mayflash F300 Arcade Joystick,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:b9,x:b0,y:b3,platform:Windows,
03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,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:Windows,
03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows,
@@ -439,6 +442,7 @@
03000000790000002201000000000000,PC 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:Windows,
030000006f0e00008501000000000000,PDP Fightpad Pro,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:b1,y:b0,platform:Windows,
030000006f0e00000901000000000000,PDP Versus Fighting,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:Windows,
+030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows,
03000000e30500009605000000000000,PlayStation Adapter,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,
030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000632500002306000000000000,PlayStation Controller,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:Windows,
@@ -463,6 +467,7 @@
03000000666600006706000000000000,PS2 Controller,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:Windows,
030000006b1400000303000000000000,PS2 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:Windows,
030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,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:b2,y:b3,platform:Windows,
+03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,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,
03000000120a00000100000000000000,PS3 Controller,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:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
@@ -735,11 +740,14 @@
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 SL6556BK,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,
030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,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:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
-03000000172700004431000000000000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000bc2000005060000000000000,Xiaomi XMGP01YM,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,-lefty:-a1,+lefty:+a2,rightx:a3,-righty:-a4,+righty:+a5,lefttrigger:b8,righttrigger:b9,platform:Windows,
+03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,x:b3,y:b4,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,platform:Windows,
03000000786901006e70000000000000,XInput 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:Windows,
xinput,XInput 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:Windows,
030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows,
03000000790000004f18000000000000,ZDT Android 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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
+03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,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:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows,
03000000120c0000101e000000000000,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:Windows,
# Mac OS X
@@ -1045,11 +1053,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
03000000050b00000579000011010000,ASUS ROG Kunai 3,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,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
05000000050b00000679000000010000,ASUS ROG Kunai 3,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,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
-03000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
-03000000503200000110000011010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
-05000000503200000110000000000000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
-05000000503200000110000044010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
-05000000503200000110000046010000,Atari Classic Controller,a:b0,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,x:b1,platform:Linux,
+03000000503200000110000000000000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+03000000503200000110000011010000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+05000000503200000110000000000000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+05000000503200000110000044010000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
+05000000503200000110000046010000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux,
03000000503200000210000000000000,Atari Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux,
03000000503200000210000011010000,Atari 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:b3,y:b2,platform:Linux,
05000000503200000210000000000000,Atari 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:b3,y:b2,platform:Linux,
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index b2a6160c6c..e11099f380 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -32,6 +32,7 @@ Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:
Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,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:Web
Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,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:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
+Linux054c0268,054c-0268-Sony PLAYSTATION(R)3 Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
# 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 1390a0a7fa..cb65d2569c 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -365,7 +365,6 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po
// Inverse lerp length to map (p_deadzone, 1) to (0, 1).
return vector * (Math::inverse_lerp(p_deadzone, 1.0f, length) / length);
}
- return vector;
}
float Input::get_joy_axis(int p_device, JoyAxis p_axis) const {
@@ -520,6 +519,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
touch_event.instantiate();
touch_event->set_pressed(mb->is_pressed());
touch_event->set_position(mb->get_position());
+ touch_event->set_double_tap(mb->is_double_click());
event_dispatch_function(touch_event);
}
}
@@ -581,6 +581,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
button_event->set_global_position(st->get_position());
button_event->set_pressed(st->is_pressed());
button_event->set_button_index(MouseButton::LEFT);
+ button_event->set_double_click(st->is_double_tap());
if (st->is_pressed()) {
button_event->set_button_mask(MouseButton(mouse_button_mask | MouseButton::MASK_LEFT));
} else {
@@ -1309,7 +1310,7 @@ void Input::parse_mapping(String p_mapping) {
JoyButton output_button = _get_output_button(output);
JoyAxis output_axis = _get_output_axis(output);
ERR_CONTINUE_MSG(output_button == JoyButton::INVALID && output_axis == JoyAxis::INVALID,
- vformat("Unrecognised output string \"%s\" in mapping:\n%s", output, p_mapping));
+ vformat("Unrecognized output string \"%s\" in mapping:\n%s", output, p_mapping));
ERR_CONTINUE_MSG(output_button != JoyButton::INVALID && output_axis != JoyAxis::INVALID,
vformat("Output string \"%s\" matched both button and axis in mapping:\n%s", output, p_mapping));
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index 16f125ff38..a7729c9af2 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -16,7 +16,7 @@ def make_default_controller_mappings(target, source, env):
g.write('#include "core/input/default_controller_mappings.h"\n')
# ensure mappings have a consistent order
- platform_mappings = OrderedDict()
+ platform_mappings: dict = OrderedDict()
for src_path in source:
with open(src_path, "r") as f:
# read mapping file and skip header
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 596b704732..0a32b4bf68 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -449,11 +449,11 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool p_exact_ma
match &= action_mask == key_mask;
}
if (match) {
- bool pressed = key->is_pressed();
+ bool key_pressed = key->is_pressed();
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = key_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float strength = key_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
@@ -610,20 +610,20 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool p_
}
bool match = button_index == mb->button_index;
- Key action_mask = get_modifiers_mask();
- Key button_mask = mb->get_modifiers_mask();
+ Key action_modifiers_mask = get_modifiers_mask();
+ Key button_modifiers_mask = mb->get_modifiers_mask();
if (mb->is_pressed()) {
- match &= (action_mask & button_mask) == action_mask;
+ match &= (action_modifiers_mask & button_modifiers_mask) == action_modifiers_mask;
}
if (p_exact_match) {
- match &= action_mask == button_mask;
+ match &= action_modifiers_mask == button_modifiers_mask;
}
if (match) {
- bool pressed = mb->is_pressed();
+ bool mb_pressed = mb->is_pressed();
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = mb_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float strength = mb_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
@@ -808,9 +808,9 @@ String InputEventMouseMotion::as_text() const {
}
String InputEventMouseMotion::to_string() {
- MouseButton button_mask = get_button_mask();
- String button_mask_string = itos((int64_t)button_mask);
- switch (button_mask) {
+ MouseButton mouse_button_mask = get_button_mask();
+ String button_mask_string = itos((int64_t)mouse_button_mask);
+ switch (mouse_button_mask) {
case MouseButton::MASK_LEFT:
button_mask_string += vformat(" (%s)", TTRGET(_mouse_button_descriptions[(size_t)MouseButton::LEFT - 1]));
break;
@@ -1045,11 +1045,11 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool p
bool match = button_index == jb->button_index;
if (match) {
- bool pressed = jb->is_pressed();
+ bool jb_pressed = jb->is_pressed();
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = jb_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float strength = jb_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
*r_strength = strength;
}
@@ -1162,6 +1162,13 @@ bool InputEventScreenTouch::is_pressed() const {
return pressed;
}
+void InputEventScreenTouch::set_double_tap(bool p_double_tap) {
+ double_tap = p_double_tap;
+}
+bool InputEventScreenTouch::is_double_tap() const {
+ return double_tap;
+}
+
Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
Ref<InputEventScreenTouch> st;
st.instantiate();
@@ -1170,6 +1177,7 @@ Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, co
st->set_index(index);
st->set_position(p_xform.xform(pos + p_local_ofs));
st->set_pressed(pressed);
+ st->set_double_tap(double_tap);
return st;
}
@@ -1182,7 +1190,8 @@ String InputEventScreenTouch::as_text() const {
String InputEventScreenTouch::to_string() {
String p = pressed ? "true" : "false";
- return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s)", index, p, String(get_position()));
+ String double_tap_string = double_tap ? "true" : "false";
+ return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s), double_tap=%s", index, p, String(get_position()), double_tap_string);
}
void InputEventScreenTouch::_bind_methods() {
@@ -1195,9 +1204,13 @@ void InputEventScreenTouch::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventScreenTouch::set_pressed);
//ClassDB::bind_method(D_METHOD("is_pressed"),&InputEventScreenTouch::is_pressed);
+ ClassDB::bind_method(D_METHOD("set_double_tap", "double_tap"), &InputEventScreenTouch::set_double_tap);
+ ClassDB::bind_method(D_METHOD("is_double_tap"), &InputEventScreenTouch::is_double_tap);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "index"), "set_index", "get_index");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "double_tap"), "set_double_tap", "is_double_tap");
}
///////////////////////////////////
@@ -1325,7 +1338,7 @@ bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_mat
return false;
}
- return p_event->is_action(action);
+ return p_event->is_action(action, p_exact_match);
}
bool InputEventAction::is_action(const StringName &p_action) const {
@@ -1340,16 +1353,16 @@ bool InputEventAction::action_match(const Ref<InputEvent> &p_event, bool p_exact
bool match = action == act->action;
if (match) {
- bool pressed = act->pressed;
+ bool act_pressed = act->pressed;
if (r_pressed != nullptr) {
- *r_pressed = pressed;
+ *r_pressed = act_pressed;
}
- float strength = pressed ? 1.0f : 0.0f;
+ float act_strength = act_pressed ? 1.0f : 0.0f;
if (r_strength != nullptr) {
- *r_strength = strength;
+ *r_strength = act_strength;
}
if (r_raw_strength != nullptr) {
- *r_raw_strength = strength;
+ *r_raw_strength = act_strength;
}
}
return match;
@@ -1549,7 +1562,7 @@ String InputEventMIDI::as_text() const {
}
String InputEventMIDI::to_string() {
- return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d", channel, message, pitch, velocity, pressure);
+ return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d, controller_number=%d, controller_value=%d", channel, message, pitch, velocity, pressure, controller_number, controller_value);
}
void InputEventMIDI::_bind_methods() {
diff --git a/core/input/input_event.h b/core/input/input_event.h
index bc3ec3e7ac..adbcb7cf68 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -353,6 +353,7 @@ class InputEventScreenTouch : public InputEventFromWindow {
int index = 0;
Vector2 pos;
bool pressed = false;
+ bool double_tap = false;
protected:
static void _bind_methods();
@@ -367,6 +368,9 @@ public:
void set_pressed(bool p_pressed);
virtual bool is_pressed() const override;
+ void set_double_tap(bool p_double_tap);
+ bool is_double_tap() const;
+
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual String as_text() const override;
virtual String to_string() override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index ce76d11b6e..1c7d71e309 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -257,7 +257,7 @@ void InputMap::load_from_project_settings() {
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- Dictionary action = ProjectSettings::get_singleton()->get(pi.name);
+ Dictionary action = GLOBAL_GET(pi.name);
float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f;
Array events = action["events"];
@@ -331,12 +331,18 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = {
{ "ui_text_caret_document_start.macos", TTRC("Caret Document Start") },
{ "ui_text_caret_document_end", TTRC("Caret Document End") },
{ "ui_text_caret_document_end.macos", TTRC("Caret Document End") },
+ { "ui_text_caret_add_below", TTRC("Caret Add Below") },
+ { "ui_text_caret_add_below.macos", TTRC("Caret Add Below") },
+ { "ui_text_caret_add_above", TTRC("Caret Add Above") },
+ { "ui_text_caret_add_above.macos", TTRC("Caret Add Above") },
{ "ui_text_scroll_up", TTRC("Scroll Up") },
{ "ui_text_scroll_up.macos", TTRC("Scroll Up") },
{ "ui_text_scroll_down", TTRC("Scroll Down") },
{ "ui_text_scroll_down.macos", TTRC("Scroll Down") },
{ "ui_text_select_all", TTRC("Select All") },
{ "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") },
+ { "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") },
+ { "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") },
{ "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") },
{ "ui_text_submit", TTRC("Text Submitted") },
{ "ui_graph_duplicate", TTRC("Duplicate Nodes") },
@@ -616,6 +622,24 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::CMD_OR_CTRL));
default_builtin_cache.insert("ui_text_caret_document_end.macos", inputs);
+ // Text Caret Addition Below/Above
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::DOWN | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_below", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::L | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_below.macos", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::UP | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_above", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::O | KeyModifierMask::SHIFT | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_caret_add_above.macos", inputs);
+
// Text Scrolling
inputs = List<Ref<InputEvent>>();
@@ -641,10 +665,18 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
default_builtin_cache.insert("ui_text_select_all", inputs);
inputs = List<Ref<InputEvent>>();
- inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
+ inputs.push_back(InputEventKey::create_reference(Key::G | KeyModifierMask::ALT));
default_builtin_cache.insert("ui_text_select_word_under_caret", inputs);
inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL));
+ default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs);
+
+ inputs = List<Ref<InputEvent>>();
+ inputs.push_back(InputEventKey::create_reference(Key::ESCAPE));
+ default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs);
+
+ inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(Key::INSERT));
default_builtin_cache.insert("ui_text_toggle_insert_mode", inputs);
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index bed41b8d89..7eb50d2261 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -36,6 +36,8 @@
#include "core/os/os.h"
#include "core/templates/local_vector.h"
+thread_local Error DirAccess::last_dir_open_error = OK;
+
String DirAccess::_get_root_path() const {
switch (_access_type) {
case ACCESS_RESOURCES:
@@ -249,6 +251,61 @@ Ref<DirAccess> DirAccess::open(const String &p_path, Error *r_error) {
return da;
}
+Ref<DirAccess> DirAccess::_open(const String &p_path) {
+ Error err = OK;
+ Ref<DirAccess> da = open(p_path, &err);
+ last_dir_open_error = err;
+ if (err) {
+ return Ref<DirAccess>();
+ }
+ return da;
+}
+
+int DirAccess::_get_drive_count() {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return d->get_drive_count();
+}
+
+String DirAccess::get_drive_name(int p_idx) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ return d->get_drive(p_idx);
+}
+
+Error DirAccess::make_dir_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->make_dir(p_dir);
+}
+
+Error DirAccess::make_dir_recursive_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->make_dir_recursive(p_dir);
+}
+
+bool DirAccess::dir_exists_absolute(const String &p_dir) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_dir);
+ return d->dir_exists(p_dir);
+}
+
+Error DirAccess::copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ // Support copying from res:// to user:// etc.
+ String from = ProjectSettings::get_singleton()->globalize_path(p_from);
+ String to = ProjectSettings::get_singleton()->globalize_path(p_to);
+ return d->copy(from, to, p_chmod_flags);
+}
+
+Error DirAccess::rename_absolute(const String &p_from, const String &p_to) {
+ Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ String from = ProjectSettings::get_singleton()->globalize_path(p_from);
+ String to = ProjectSettings::get_singleton()->globalize_path(p_to);
+ return d->rename(from, to);
+}
+
+Error DirAccess::remove_absolute(const String &p_path) {
+ Ref<DirAccess> d = DirAccess::create_for_path(p_path);
+ return d->remove(p_path);
+}
+
Ref<DirAccess> DirAccess::create(AccessType p_access) {
Ref<DirAccess> da = create_func[p_access] ? create_func[p_access]() : nullptr;
if (da.is_valid()) {
@@ -266,6 +323,10 @@ Ref<DirAccess> DirAccess::create(AccessType p_access) {
return da;
}
+Error DirAccess::get_open_error() {
+ return last_dir_open_error;
+}
+
String DirAccess::get_full_path(const String &p_path, AccessType p_access) {
Ref<DirAccess> d = DirAccess::create(p_access);
if (d.is_null()) {
@@ -290,7 +351,7 @@ Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) {
const size_t copy_buffer_limit = 65536; // 64 KB
fsrc->seek_end(0);
- int size = fsrc->get_position();
+ uint64_t size = fsrc->get_position();
fsrc->seek(0);
err = OK;
size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit);
@@ -424,3 +485,104 @@ bool DirAccess::exists(String p_dir) {
Ref<DirAccess> da = DirAccess::create_for_path(p_dir);
return da->change_dir(p_dir) == OK;
}
+
+PackedStringArray DirAccess::get_files() {
+ return _get_contents(false);
+}
+
+PackedStringArray DirAccess::get_files_at(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::open(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
+ return da->get_files();
+}
+
+PackedStringArray DirAccess::get_directories() {
+ return _get_contents(true);
+}
+
+PackedStringArray DirAccess::get_directories_at(const String &p_path) {
+ Ref<DirAccess> da = DirAccess::open(p_path);
+ ERR_FAIL_COND_V_MSG(da.is_null(), PackedStringArray(), vformat("Couldn't open directory at path \"%s\".", p_path));
+ return da->get_directories();
+}
+
+PackedStringArray DirAccess::_get_contents(bool p_directories) {
+ PackedStringArray ret;
+
+ list_dir_begin();
+ String s = _get_next();
+ while (!s.is_empty()) {
+ if (current_is_dir() == p_directories) {
+ ret.append(s);
+ }
+ s = _get_next();
+ }
+
+ ret.sort();
+ return ret;
+}
+
+String DirAccess::_get_next() {
+ String next = get_next();
+ while (!next.is_empty() && ((!include_navigational && (next == "." || next == "..")) || (!include_hidden && current_is_hidden()))) {
+ next = get_next();
+ }
+ return next;
+}
+
+void DirAccess::set_include_navigational(bool p_enable) {
+ include_navigational = p_enable;
+}
+
+bool DirAccess::get_include_navigational() const {
+ return include_navigational;
+}
+
+void DirAccess::set_include_hidden(bool p_enable) {
+ include_hidden = p_enable;
+}
+
+bool DirAccess::get_include_hidden() const {
+ return include_hidden;
+}
+
+void DirAccess::_bind_methods() {
+ ClassDB::bind_static_method("DirAccess", D_METHOD("open", "path"), &DirAccess::_open);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_open_error"), &DirAccess::get_open_error);
+
+ ClassDB::bind_method(D_METHOD("list_dir_begin"), &DirAccess::list_dir_begin, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_next"), &DirAccess::_get_next);
+ ClassDB::bind_method(D_METHOD("current_is_dir"), &DirAccess::current_is_dir);
+ ClassDB::bind_method(D_METHOD("list_dir_end"), &DirAccess::list_dir_end);
+ ClassDB::bind_method(D_METHOD("get_files"), &DirAccess::get_files);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_files_at", "path"), &DirAccess::get_files_at);
+ ClassDB::bind_method(D_METHOD("get_directories"), &DirAccess::get_directories);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_directories_at", "path"), &DirAccess::get_directories_at);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_count"), &DirAccess::_get_drive_count);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("get_drive_name", "idx"), &DirAccess::get_drive_name);
+ ClassDB::bind_method(D_METHOD("get_current_drive"), &DirAccess::get_current_drive);
+ ClassDB::bind_method(D_METHOD("change_dir", "to_dir"), &DirAccess::change_dir);
+ ClassDB::bind_method(D_METHOD("get_current_dir", "include_drive"), &DirAccess::get_current_dir, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("make_dir", "path"), &DirAccess::make_dir);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_absolute", "path"), &DirAccess::make_dir_absolute);
+ ClassDB::bind_method(D_METHOD("make_dir_recursive", "path"), &DirAccess::make_dir_recursive);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("make_dir_recursive_absolute", "path"), &DirAccess::make_dir_recursive_absolute);
+ ClassDB::bind_method(D_METHOD("file_exists", "path"), &DirAccess::file_exists);
+ ClassDB::bind_method(D_METHOD("dir_exists", "path"), &DirAccess::dir_exists);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("dir_exists_absolute", "path"), &DirAccess::dir_exists_absolute);
+ ClassDB::bind_method(D_METHOD("get_space_left"), &DirAccess::get_space_left);
+ ClassDB::bind_method(D_METHOD("copy", "from", "to", "chmod_flags"), &DirAccess::copy, DEFVAL(-1));
+ ClassDB::bind_static_method("DirAccess", D_METHOD("copy_absolute", "from", "to", "chmod_flags"), &DirAccess::copy_absolute, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("rename", "from", "to"), &DirAccess::rename);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("rename_absolute", "from", "to"), &DirAccess::rename_absolute);
+ ClassDB::bind_method(D_METHOD("remove", "path"), &DirAccess::remove);
+ ClassDB::bind_static_method("DirAccess", D_METHOD("remove_absolute", "path"), &DirAccess::remove_absolute);
+
+ ClassDB::bind_method(D_METHOD("set_include_navigational", "enable"), &DirAccess::set_include_navigational);
+ ClassDB::bind_method(D_METHOD("get_include_navigational"), &DirAccess::get_include_navigational);
+ ClassDB::bind_method(D_METHOD("set_include_hidden", "enable"), &DirAccess::set_include_hidden);
+ ClassDB::bind_method(D_METHOD("get_include_hidden"), &DirAccess::get_include_hidden);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_navigational"), "set_include_navigational", "get_include_navigational");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "include_hidden"), "set_include_hidden", "get_include_hidden");
+}
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index 2469c2a080..bd24214e73 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -37,6 +37,8 @@
//@ TODO, excellent candidate for THREAD_SAFE MACRO, should go through all these and add THREAD_SAFE where it applies
class DirAccess : public RefCounted {
+ GDCLASS(DirAccess, RefCounted);
+
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -50,10 +52,18 @@ public:
private:
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object
+ static Ref<DirAccess> _open(const String &p_path);
Error _copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod_flags, bool p_copy_links);
+ PackedStringArray _get_contents(bool p_directories);
+
+ thread_local static Error last_dir_open_error;
+ bool include_navigational = false;
+ bool include_hidden = false;
protected:
+ static void _bind_methods();
+
String _get_root_path() const;
virtual String _get_root_string() const;
@@ -118,6 +128,7 @@ public:
static Ref<DirAccess> create_for_path(const String &p_path);
static Ref<DirAccess> create(AccessType p_access);
+ static Error get_open_error();
template <class T>
static void make_default(AccessType p_access) {
@@ -126,6 +137,28 @@ public:
static Ref<DirAccess> open(const String &p_path, Error *r_error = nullptr);
+ static int _get_drive_count();
+ static String get_drive_name(int p_idx);
+
+ static Error make_dir_absolute(const String &p_dir);
+ static Error make_dir_recursive_absolute(const String &p_dir);
+ static bool dir_exists_absolute(const String &p_dir);
+
+ static Error copy_absolute(const String &p_from, const String &p_to, int p_chmod_flags = -1);
+ static Error rename_absolute(const String &p_from, const String &p_to);
+ static Error remove_absolute(const String &p_path);
+
+ PackedStringArray get_files();
+ static PackedStringArray get_files_at(const String &p_path);
+ PackedStringArray get_directories();
+ static PackedStringArray get_directories_at(const String &p_path);
+ String _get_next();
+
+ void set_include_navigational(bool p_enable);
+ bool get_include_navigational() const;
+ void set_include_hidden(bool p_enable);
+ bool get_include_hidden() const;
+
DirAccess() {}
virtual ~DirAccess() {}
};
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 72c00bd678..cb25564342 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/crypto/crypto_core.h"
+#include "core/io/file_access_compressed.h"
+#include "core/io/file_access_encrypted.h"
#include "core/io/file_access_pack.h"
#include "core/io/marshalls.h"
#include "core/os/os.h"
@@ -41,6 +43,7 @@ FileAccess::CreateFunc FileAccess::create_func[ACCESS_MAX] = { nullptr, nullptr
FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr;
bool FileAccess::backup_save = false;
+thread_local Error FileAccess::last_file_open_error = OK;
Ref<FileAccess> FileAccess::create(AccessType p_access) {
ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr);
@@ -81,7 +84,7 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) {
}
Error FileAccess::reopen(const String &p_path, int p_mode_flags) {
- return _open(p_path, p_mode_flags);
+ return open_internal(p_path, p_mode_flags);
}
Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *r_error) {
@@ -99,7 +102,7 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
}
ret = create_for_path(p_path);
- Error err = ret->_open(p_path, p_mode_flags);
+ Error err = ret->open_internal(p_path, p_mode_flags);
if (r_error) {
*r_error = err;
@@ -111,6 +114,66 @@ Ref<FileAccess> FileAccess::open(const String &p_path, int p_mode_flags, Error *
return ret;
}
+Ref<FileAccess> FileAccess::_open(const String &p_path, ModeFlags p_mode_flags) {
+ Error err = OK;
+ Ref<FileAccess> fa = open(p_path, p_mode_flags, &err);
+ last_file_open_error = err;
+ if (err) {
+ return Ref<FileAccess>();
+ }
+ return fa;
+}
+
+Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
+ Ref<FileAccess> fa = _open(p_path, p_mode_flags);
+ if (fa.is_null()) {
+ return fa;
+ }
+
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+ return fae;
+}
+
+Ref<FileAccess> FileAccess::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
+ Ref<FileAccess> fa = _open(p_path, p_mode_flags);
+ if (fa.is_null()) {
+ return fa;
+ }
+
+ Ref<FileAccessEncrypted> fae;
+ fae.instantiate();
+ Error err = fae->open_and_parse_password(fa, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+ return fae;
+}
+
+Ref<FileAccess> FileAccess::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
+ Ref<FileAccessCompressed> fac;
+ fac.instantiate();
+ fac->configure("GCPF", (Compression::Mode)p_compress_mode);
+ Error err = fac->open_internal(p_path, p_mode_flags);
+
+ if (err) {
+ last_file_open_error = err;
+ return Ref<FileAccess>();
+ }
+
+ return fac;
+}
+
+Error FileAccess::get_open_error() {
+ return last_file_open_error;
+}
+
FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) {
return create_func[p_access];
}
@@ -227,6 +290,20 @@ real_t FileAccess::get_real() const {
}
}
+Variant FileAccess::get_var(bool p_allow_objects) const {
+ uint32_t len = get_32();
+ Vector<uint8_t> buff = _get_buffer(len);
+ ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
+
+ const uint8_t *r = buff.ptr();
+
+ Variant v;
+ Error err = decode_variant(v, &r[0], len, nullptr, p_allow_objects);
+ ERR_FAIL_COND_V_MSG(err != OK, Variant(), "Error when trying to encode Variant.");
+
+ return v;
+}
+
double FileAccess::get_double() const {
MarshallDouble m;
m.l = get_64();
@@ -370,6 +447,17 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const {
return strings;
}
+String FileAccess::get_as_text(bool p_skip_cr) const {
+ uint64_t original_pos = get_position();
+ const_cast<FileAccess *>(this)->seek(0);
+
+ String text = get_as_utf8_string(p_skip_cr);
+
+ const_cast<FileAccess *>(this)->seek(original_pos);
+
+ return text;
+}
+
uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
@@ -381,6 +469,27 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i;
}
+Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
+ Vector<uint8_t> data;
+
+ ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
+ if (p_length == 0) {
+ return data;
+ }
+
+ Error err = data.resize(p_length);
+ ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements.");
+
+ uint8_t *w = data.ptrw();
+ int64_t len = get_buffer(&w[0], p_length);
+
+ if (len < p_length) {
+ data.resize(len);
+ }
+
+ return data;
+}
+
String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
Vector<uint8_t> sourcef;
uint64_t len = get_length();
@@ -439,7 +548,7 @@ void FileAccess::store_64(uint64_t p_dest) {
}
void FileAccess::store_real(real_t p_real) {
- if (sizeof(real_t) == 4) {
+ if constexpr (sizeof(real_t) == 4) {
store_float(p_real);
} else {
store_double(p_real);
@@ -554,6 +663,33 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
}
+void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
+ uint64_t len = p_buffer.size();
+ if (len == 0) {
+ return;
+ }
+
+ const uint8_t *r = p_buffer.ptr();
+
+ store_buffer(&r[0], len);
+}
+
+void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
+ int len;
+ Error err = encode_variant(p_var, nullptr, len, p_full_objects);
+ ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
+
+ Vector<uint8_t> buff;
+ buff.resize(len);
+
+ uint8_t *w = buff.ptrw();
+ err = encode_variant(p_var, &w[0], len, p_full_objects);
+ ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
+
+ store_32(len);
+ _store_buffer(buff);
+}
+
Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_error) {
Ref<FileAccess> f = FileAccess::open(p_path, READ, r_error);
if (f.is_null()) {
@@ -666,3 +802,69 @@ String FileAccess::get_sha256(const String &p_file) {
return String::hex_encode_buffer(hash, 32);
}
+
+void FileAccess::_bind_methods() {
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open", "path", "flags"), &FileAccess::_open);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::open_encrypted);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_encrypted_with_pass", "path", "mode_flags", "pass"), &FileAccess::open_encrypted_pass);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &FileAccess::open_compressed, DEFVAL(0));
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_open_error"), &FileAccess::get_open_error);
+
+ ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush);
+ ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path);
+ ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute);
+ ClassDB::bind_method(D_METHOD("is_open"), &FileAccess::is_open);
+ ClassDB::bind_method(D_METHOD("seek", "position"), &FileAccess::seek);
+ ClassDB::bind_method(D_METHOD("seek_end", "position"), &FileAccess::seek_end, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_position"), &FileAccess::get_position);
+ ClassDB::bind_method(D_METHOD("get_length"), &FileAccess::get_length);
+ ClassDB::bind_method(D_METHOD("eof_reached"), &FileAccess::eof_reached);
+ ClassDB::bind_method(D_METHOD("get_8"), &FileAccess::get_8);
+ ClassDB::bind_method(D_METHOD("get_16"), &FileAccess::get_16);
+ ClassDB::bind_method(D_METHOD("get_32"), &FileAccess::get_32);
+ ClassDB::bind_method(D_METHOD("get_64"), &FileAccess::get_64);
+ ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
+ ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
+ ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
+ ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
+ ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
+ ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
+ ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_md5", "path"), &FileAccess::get_md5);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_sha256", "path"), &FileAccess::get_sha256);
+ ClassDB::bind_method(D_METHOD("is_big_endian"), &FileAccess::is_big_endian);
+ ClassDB::bind_method(D_METHOD("set_big_endian", "big_endian"), &FileAccess::set_big_endian);
+ ClassDB::bind_method(D_METHOD("get_error"), &FileAccess::get_error);
+ ClassDB::bind_method(D_METHOD("get_var", "allow_objects"), &FileAccess::get_var, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("store_8", "value"), &FileAccess::store_8);
+ ClassDB::bind_method(D_METHOD("store_16", "value"), &FileAccess::store_16);
+ ClassDB::bind_method(D_METHOD("store_32", "value"), &FileAccess::store_32);
+ ClassDB::bind_method(D_METHOD("store_64", "value"), &FileAccess::store_64);
+ ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
+ ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
+ ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
+ ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
+ ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
+ ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
+ ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
+ ClassDB::bind_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var, DEFVAL(false));
+
+ ClassDB::bind_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string);
+ ClassDB::bind_method(D_METHOD("get_pascal_string"), &FileAccess::get_pascal_string);
+
+ ClassDB::bind_static_method("FileAccess", D_METHOD("file_exists", "path"), &FileAccess::exists);
+ ClassDB::bind_static_method("FileAccess", D_METHOD("get_modified_time", "file"), &FileAccess::get_modified_time);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian");
+
+ BIND_ENUM_CONSTANT(READ);
+ BIND_ENUM_CONSTANT(WRITE);
+ BIND_ENUM_CONSTANT(READ_WRITE);
+ BIND_ENUM_CONSTANT(WRITE_READ);
+
+ BIND_ENUM_CONSTANT(COMPRESSION_FASTLZ);
+ BIND_ENUM_CONSTANT(COMPRESSION_DEFLATE);
+ BIND_ENUM_CONSTANT(COMPRESSION_ZSTD);
+ BIND_ENUM_CONSTANT(COMPRESSION_GZIP);
+}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index fc0eb95d44..8ca44306a0 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -31,6 +31,7 @@
#ifndef FILE_ACCESS_H
#define FILE_ACCESS_H
+#include "core/io/compression.h"
#include "core/math/math_defs.h"
#include "core/object/ref_counted.h"
#include "core/os/memory.h"
@@ -42,6 +43,8 @@
*/
class FileAccess : public RefCounted {
+ GDCLASS(FileAccess, RefCounted);
+
public:
enum AccessType {
ACCESS_RESOURCES,
@@ -50,6 +53,20 @@ public:
ACCESS_MAX
};
+ enum ModeFlags {
+ READ = 1,
+ WRITE = 2,
+ READ_WRITE = 3,
+ WRITE_READ = 7,
+ };
+
+ enum CompressionMode {
+ COMPRESSION_FASTLZ = Compression::MODE_FASTLZ,
+ COMPRESSION_DEFLATE = Compression::MODE_DEFLATE,
+ COMPRESSION_ZSTD = Compression::MODE_ZSTD,
+ COMPRESSION_GZIP = Compression::MODE_GZIP
+ };
+
typedef void (*FileCloseFailNotify)(const String &);
typedef Ref<FileAccess> (*CreateFunc)();
@@ -60,15 +77,19 @@ public:
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
protected:
+ static void _bind_methods();
+
AccessType get_access_type() const;
String fix_path(const String &p_path) const;
- virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0;
+ virtual void _set_access_type(AccessType p_access);
static FileCloseFailNotify close_fail_notify;
private:
static bool backup_save;
+ thread_local static Error last_file_open_error;
AccessType _access_type = ACCESS_FILESYSTEM;
static CreateFunc create_func[ACCESS_MAX]; /** default file access creation function for a platform */
@@ -77,18 +98,11 @@ private:
return memnew(T);
}
+ static Ref<FileAccess> _open(const String &p_path, ModeFlags p_mode_flags);
+
public:
static void set_file_close_fail_notify_callback(FileCloseFailNotify p_cbk) { close_fail_notify = p_cbk; }
- virtual void _set_access_type(AccessType p_access);
-
- enum ModeFlags {
- READ = 1,
- WRITE = 2,
- READ_WRITE = 3,
- WRITE_READ = 7,
- };
-
virtual bool is_open() const = 0; ///< true when file is open
virtual String get_path() const { return ""; } /// returns the path for the current open file
@@ -110,10 +124,14 @@ public:
virtual double get_double() const;
virtual real_t get_real() const;
+ Variant get_var(bool p_allow_objects = false) const;
+
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
+ Vector<uint8_t> _get_buffer(int64_t p_length) const;
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
+ String get_as_text(bool p_skip_cr = false) const;
virtual String get_as_utf8_string(bool p_skip_cr = false) const;
/**
@@ -144,6 +162,9 @@ public:
virtual String get_pascal_string();
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ void _store_buffer(const Vector<uint8_t> &p_buffer);
+
+ void store_var(const Variant &p_var, bool p_full_objects = false);
virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists
@@ -152,6 +173,12 @@ public:
static Ref<FileAccess> create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files.
static Ref<FileAccess> create_for_path(const String &p_path);
static Ref<FileAccess> open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); /// Create a file access (for the current platform) this is the only portable way of accessing files.
+
+ static Ref<FileAccess> open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ static Ref<FileAccess> open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
+ static Ref<FileAccess> open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
+ static Error get_open_error();
+
static CreateFunc get_create_func(AccessType p_access);
static bool exists(const String &p_name); ///< return true if a file exists
static uint64_t get_modified_time(const String &p_file);
@@ -177,4 +204,7 @@ public:
virtual ~FileAccess() {}
};
+VARIANT_ENUM_CAST(FileAccess::CompressionMode);
+VARIANT_ENUM_CAST(FileAccess::ModeFlags);
+
#endif // FILE_ACCESS_H
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 1d0a718166..d2c8a88269 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -95,7 +95,7 @@ Error FileAccessCompressed::open_after_magic(Ref<FileAccess> p_base) {
return ret == -1 ? ERR_FILE_CORRUPT : OK;
}
-Error FileAccessCompressed::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessCompressed::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags == READ_WRITE, ERR_UNAVAILABLE);
_close();
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index e41491a92c..ee114c2c65 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -70,7 +70,7 @@ public:
Error open_after_magic(Ref<FileAccess> p_base);
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index d1b014a0be..e7b2a2dfee 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -102,16 +102,16 @@ Error FileAccessEncrypted::open_and_parse(Ref<FileAccess> p_base, const Vector<u
Error FileAccessEncrypted::open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode) {
String cs = p_key.md5_text();
ERR_FAIL_COND_V(cs.length() != 32, ERR_INVALID_PARAMETER);
- Vector<uint8_t> key;
- key.resize(32);
+ Vector<uint8_t> key_md5;
+ key_md5.resize(32);
for (int i = 0; i < 32; i++) {
- key.write[i] = cs[i];
+ key_md5.write[i] = cs[i];
}
- return open_and_parse(p_base, key, p_mode);
+ return open_and_parse(p_base, key_md5, p_mode);
}
-Error FileAccessEncrypted::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessEncrypted::open_internal(const String &p_path, int p_mode_flags) {
return OK;
}
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 6200f87a7a..6b4588841d 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -60,7 +60,7 @@ public:
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual String get_path() const override; /// returns the path for the current open file
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 499d001234..21ded4247f 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -78,7 +78,7 @@ Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
return OK;
}
-Error FileAccessMemory::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
String name = fix_path(p_path);
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index f2bd2aa832..b1f408eb98 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -45,7 +45,7 @@ public:
static void cleanup();
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 1365b4b593..87f3f66597 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -137,12 +137,12 @@ void FileAccessNetworkClient::_thread_func() {
int64_t offset = get_64();
int32_t len = get_32();
- Vector<uint8_t> block;
- block.resize(len);
- client->get_data(block.ptrw(), len);
+ Vector<uint8_t> resp_block;
+ resp_block.resize(len);
+ client->get_data(resp_block.ptrw(), len);
if (fa) { //may have been queued
- fa->_set_block(offset, block);
+ fa->_set_block(offset, resp_block);
}
} break;
@@ -252,7 +252,7 @@ void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) {
pages.resize(pc);
}
-Error FileAccessNetwork::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessNetwork::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags != READ, ERR_UNAVAILABLE);
_close();
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index ceadc715a1..ee92d3b9db 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -132,7 +132,7 @@ public:
RESPONSE_GET_MODTIME,
};
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index adae0db0f4..dfcce30ab5 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -259,7 +259,7 @@ Ref<FileAccess> PackedSourcePCK::get_file(const String &p_path, PackedData::Pack
//////////////////////////////////////////////////////////////////
-Error FileAccessPack::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessPack::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_V(ERR_UNAVAILABLE);
return ERR_UNAVAILABLE;
}
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 023758ac0f..4b9b49a161 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -148,7 +148,7 @@ class FileAccessPack : public FileAccess {
uint64_t off;
Ref<FileAccess> f;
- virtual Error _open(const String &p_path, int p_mode_flags) override;
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override;
virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index 17f2335a8e..72503851c1 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -234,7 +234,7 @@ ZipArchive::~ZipArchive() {
packages.clear();
}
-Error FileAccessZip::_open(const String &p_path, int p_mode_flags) {
+Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) {
_close();
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
@@ -337,7 +337,7 @@ bool FileAccessZip::file_exists(const String &p_name) {
}
FileAccessZip::FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file) {
- _open(p_path, FileAccess::READ);
+ open_internal(p_path, FileAccess::READ);
}
FileAccessZip::~FileAccessZip() {
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 74a48192f3..6d61b9a291 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -85,7 +85,7 @@ class FileAccessZip : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
virtual void seek(uint64_t p_position) override; ///< seek to a given position
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index 5c1d00a330..aff79320ca 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -358,38 +358,38 @@ Error HTTPClientTCP::poll() {
} break;
}
} else if (tls) {
- Ref<StreamPeerTLS> tls;
+ Ref<StreamPeerTLS> tls_conn;
if (!handshaking) {
// Connect the StreamPeerTLS and start handshaking.
- tls = Ref<StreamPeerTLS>(StreamPeerTLS::create());
- tls->set_blocking_handshake_enabled(false);
- Error err = tls->connect_to_stream(tcp_connection, tls_verify_host, conn_host);
+ tls_conn = Ref<StreamPeerTLS>(StreamPeerTLS::create());
+ tls_conn->set_blocking_handshake_enabled(false);
+ Error err = tls_conn->connect_to_stream(tcp_connection, tls_verify_host, conn_host);
if (err != OK) {
close();
status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- connection = tls;
+ connection = tls_conn;
handshaking = true;
} else {
// We are already handshaking, which means we can use your already active TLS connection.
- tls = static_cast<Ref<StreamPeerTLS>>(connection);
- if (tls.is_null()) {
+ tls_conn = static_cast<Ref<StreamPeerTLS>>(connection);
+ if (tls_conn.is_null()) {
close();
status = STATUS_TLS_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- tls->poll(); // Try to finish the handshake.
+ tls_conn->poll(); // Try to finish the handshake.
}
- if (tls->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
+ if (tls_conn->get_status() == StreamPeerTLS::STATUS_CONNECTED) {
// Handshake has been successful.
handshaking = false;
ip_candidates.clear();
status = STATUS_CONNECTED;
return OK;
- } else if (tls->get_status() != StreamPeerTLS::STATUS_HANDSHAKING) {
+ } else if (tls_conn->get_status() != StreamPeerTLS::STATUS_HANDSHAKING) {
// Handshake has failed.
close();
status = STATUS_TLS_HANDSHAKE_ERROR;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 812bfa8263..65addaf964 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -444,7 +444,7 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
uint8_t rgba[4] = { 0, 0, 0, 255 };
- if (read_gray) {
+ if constexpr (read_gray) {
rgba[0] = rofs[0];
rgba[1] = rofs[0];
rgba[2] = rofs[0];
@@ -454,11 +454,11 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
}
}
- if (read_alpha || write_alpha) {
+ if constexpr (read_alpha || write_alpha) {
rgba[3] = read_alpha ? rofs[read_bytes] : 255;
}
- if (write_gray) {
+ if constexpr (write_gray) {
//TODO: not correct grayscale, should use fixed point version of actual weights
wofs[0] = uint8_t((uint16_t(rgba[0]) + uint16_t(rgba[1]) + uint16_t(rgba[2])) / 3);
} else {
@@ -467,7 +467,7 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p
}
}
- if (write_alpha) {
+ if constexpr (write_alpha) {
wofs[write_bytes] = rgba[3];
}
}
@@ -640,7 +640,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_
double xfac = (double)width / p_dst_width;
double yfac = (double)height / p_dst_height;
// coordinates of source points and coefficients
- double ox, oy, dx, dy, k1, k2;
+ double ox, oy, dx, dy;
int ox1, oy1, ox2, oy2;
// destination pixel values
// width and height decreased by 1
@@ -671,7 +671,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_
for (int n = -1; n < 3; n++) {
// get Y coefficient
- k1 = _bicubic_interp_kernel(dy - (double)n);
+ [[maybe_unused]] double k1 = _bicubic_interp_kernel(dy - (double)n);
oy2 = oy1 + n;
if (oy2 < 0) {
@@ -683,7 +683,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_
for (int m = -1; m < 3; m++) {
// get X coefficient
- k2 = k1 * _bicubic_interp_kernel((double)m - dx);
+ [[maybe_unused]] double k2 = k1 * _bicubic_interp_kernel((double)m - dx);
ox2 = ox1 + m;
if (ox2 < 0) {
@@ -697,7 +697,7 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_
const T *__restrict p = ((T *)p_src) + (oy2 * p_src_width + ox2) * CC;
for (int i = 0; i < CC; i++) {
- if (sizeof(T) == 2) { //half float
+ if constexpr (sizeof(T) == 2) { //half float
color[i] = Math::half_to_float(p[i]);
} else {
color[i] += p[i] * k2;
@@ -707,9 +707,9 @@ static void _scale_cubic(const uint8_t *__restrict p_src, uint8_t *__restrict p_
}
for (int i = 0; i < CC; i++) {
- if (sizeof(T) == 1) { //byte
+ if constexpr (sizeof(T) == 1) { //byte
dst[i] = CLAMP(Math::fast_ftoi(color[i]), 0, 255);
- } else if (sizeof(T) == 2) { //half float
+ } else if constexpr (sizeof(T) == 2) { //half float
dst[i] = Math::make_half_float(color[i]);
} else {
dst[i] = color[i];
@@ -758,7 +758,7 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict
src_xofs_right *= CC;
for (uint32_t l = 0; l < CC; l++) {
- if (sizeof(T) == 1) { //uint8
+ if constexpr (sizeof(T) == 1) { //uint8
uint32_t p00 = p_src[y_ofs_up + src_xofs_left + l] << FRAC_BITS;
uint32_t p10 = p_src[y_ofs_up + src_xofs_right + l] << FRAC_BITS;
uint32_t p01 = p_src[y_ofs_down + src_xofs_left + l] << FRAC_BITS;
@@ -769,7 +769,7 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict
uint32_t interp = interp_up + (((interp_down - interp_up) * src_yofs_frac) >> FRAC_BITS);
interp >>= FRAC_BITS;
p_dst[i * p_dst_width * CC + j * CC + l] = uint8_t(interp);
- } else if (sizeof(T) == 2) { //half float
+ } else if constexpr (sizeof(T) == 2) { //half float
float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS);
float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS);
@@ -786,7 +786,7 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict
float interp = interp_up + ((interp_down - interp_up) * yofs_frac);
dst[i * p_dst_width * CC + j * CC + l] = Math::make_half_float(interp);
- } else if (sizeof(T) == 4) { //float
+ } else if constexpr (sizeof(T) == 4) { //float
float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS);
float yofs_frac = float(src_yofs_frac) / (1 << FRAC_BITS);
@@ -877,7 +877,7 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict
const T *__restrict src_data = ((const T *)p_src) + (buffer_y * src_width + target_x) * CC;
for (uint32_t i = 0; i < CC; i++) {
- if (sizeof(T) == 2) { //half float
+ if constexpr (sizeof(T) == 2) { //half float
pixel[i] += Math::half_to_float(src_data[i]) * lanczos_val;
} else {
pixel[i] += src_data[i] * lanczos_val;
@@ -934,9 +934,9 @@ static void _scale_lanczos(const uint8_t *__restrict p_src, uint8_t *__restrict
for (uint32_t i = 0; i < CC; i++) {
pixel[i] /= weight;
- if (sizeof(T) == 1) { //byte
+ if constexpr (sizeof(T) == 1) { //byte
dst_data[i] = CLAMP(Math::fast_ftoi(pixel[i]), 0, 255);
- } else if (sizeof(T) == 2) { //half float
+ } else if constexpr (sizeof(T) == 2) { //half float
dst_data[i] = Math::make_half_float(pixel[i]);
} else { // float
dst_data[i] = pixel[i];
@@ -982,7 +982,7 @@ void Image::resize_to_po2(bool p_square, Interpolation p_interpolation) {
}
void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
- ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use create() or create_from_data() first.");
+ ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use set_data() first.");
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in compressed or custom image formats.");
bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */;
@@ -1017,7 +1017,7 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) {
}
bool interpolate_mipmaps = mipmap_aware && mip1 != mip2;
if (interpolate_mipmaps) {
- dst2.create(p_width, p_height, false, format);
+ dst2.initialize_data(p_width, p_height, false, format);
}
bool had_mipmaps = mipmaps;
@@ -2016,9 +2016,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con
uint8_t* wr = imgdata.ptrw();
memcpy(wr.ptr(), ptr, size);
wr = uint8_t*();
- Ref<Image> im;
- im.instantiate();
- im->create(w, h, false, format, imgdata);
+ Ref<Image> im = Image::create_from_data(w, h, false, format, imgdata);
im->save_png("res://mipmap_" + itos(i) + ".png");
}
#endif
@@ -2051,7 +2049,25 @@ Vector<uint8_t> Image::get_data() const {
return data;
}
-void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+Ref<Image> Image::create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
+ Ref<Image> image;
+ image.instantiate();
+ image->initialize_data(p_width, p_height, p_use_mipmaps, p_format);
+ return image;
+}
+
+Ref<Image> Image::create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ Ref<Image> image;
+ image.instantiate();
+ image->initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
+ return image;
+}
+
+void Image::set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+ initialize_data(p_width, p_height, p_use_mipmaps, p_format, p_data);
+}
+
+void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
@@ -2077,7 +2093,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
format = p_format;
}
-void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
+void Image::initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
ERR_FAIL_COND_MSG(p_width <= 0, "The Image width specified (" + itos(p_width) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_height <= 0, "The Image height specified (" + itos(p_height) + " pixels) must be greater than 0 pixels.");
ERR_FAIL_COND_MSG(p_width > MAX_WIDTH,
@@ -2115,7 +2131,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma
mipmaps = p_use_mipmaps;
}
-void Image::create(const char **p_xpm) {
+void Image::initialize_data(const char **p_xpm) {
int size_width = 0;
int size_height = 0;
int pixelchars = 0;
@@ -2230,7 +2246,7 @@ void Image::create(const char **p_xpm) {
}
if (line == colormap_size) {
status = READING_PIXELS;
- create(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
+ initialize_data(size_width, size_height, false, has_alpha ? FORMAT_RGBA8 : FORMAT_RGB8);
data_write = data.ptrw();
pixel_size = has_alpha ? 4 : 3;
}
@@ -2559,7 +2575,7 @@ Image::Image(const char **p_xpm) {
mipmaps = false;
format = FORMAT_L8;
- create(p_xpm);
+ initialize_data(p_xpm);
}
Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
@@ -2568,7 +2584,7 @@ Image::Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
mipmaps = p_use_mipmaps;
format = FORMAT_L8;
- create(p_width, p_height, p_use_mipmaps, p_format);
+ initialize_data(p_width, p_height, p_use_mipmaps, p_format);
}
Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
@@ -2577,7 +2593,7 @@ Image::Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const V
mipmaps = p_mipmaps;
format = FORMAT_L8;
- create(p_width, p_height, p_mipmaps, p_format, p_data);
+ initialize_data(p_width, p_height, p_mipmaps, p_format, p_data);
}
Rect2i Image::get_used_rect() const {
@@ -2620,9 +2636,9 @@ Rect2i Image::get_used_rect() const {
}
}
-Ref<Image> Image::get_rect(const Rect2i &p_area) const {
- Ref<Image> img = memnew(Image(p_area.size.x, p_area.size.y, mipmaps, format));
- img->blit_rect(Ref<Image>((Image *)this), p_area, Point2i(0, 0));
+Ref<Image> Image::get_region(const Rect2i &p_region) const {
+ Ref<Image> img = memnew(Image(p_region.size.x, p_region.size.y, mipmaps, format));
+ img->blit_rect(Ref<Image>((Image *)this), p_region, Point2i(0, 0));
return img;
}
@@ -2846,6 +2862,9 @@ void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_s
}
void Image::fill(const Color &p_color) {
+ if (data.size() == 0) {
+ return;
+ }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
uint8_t *dst_data_ptr = data.ptrw();
@@ -2859,6 +2878,9 @@ void Image::fill(const Color &p_color) {
}
void Image::fill_rect(const Rect2i &p_rect, const Color &p_color) {
+ if (data.size() == 0) {
+ return;
+ }
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
@@ -2931,7 +2953,7 @@ void Image::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND(ddformat == FORMAT_MAX);
- create(dwidth, dheight, dmipmaps, ddformat, ddata);
+ initialize_data(dwidth, dheight, dmipmaps, ddformat, ddata);
}
Dictionary Image::_get_data() const {
@@ -3294,8 +3316,9 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps);
- 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_static_method("Image", D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::create_empty);
+ ClassDB::bind_static_method("Image", D_METHOD("create_from_data", "width", "height", "use_mipmaps", "format", "data"), &Image::create_from_data);
+ ClassDB::bind_method(D_METHOD("set_data", "width", "height", "use_mipmaps", "format", "data"), &Image::set_data);
ClassDB::bind_method(D_METHOD("is_empty"), &Image::is_empty);
@@ -3339,7 +3362,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("fill_rect", "rect", "color"), &Image::fill_rect);
ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect);
- ClassDB::bind_method(D_METHOD("get_rect", "rect"), &Image::get_rect);
+ ClassDB::bind_method(D_METHOD("get_region", "region"), &Image::get_region);
ClassDB::bind_method(D_METHOD("copy_from", "src"), &Image::copy_internals_from);
@@ -3460,9 +3483,7 @@ Ref<Image> Image::rgbe_to_srgb() {
ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>());
- Ref<Image> new_image;
- new_image.instantiate();
- new_image->create(width, height, false, Image::FORMAT_RGB8);
+ Ref<Image> new_image = create_empty(width, height, false, Image::FORMAT_RGB8);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
@@ -3503,6 +3524,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const {
void Image::bump_map_to_normal_map(float bump_scale) {
ERR_FAIL_COND(!_can_modify(format));
+ clear_mipmaps();
convert(Image::FORMAT_RF);
Vector<uint8_t> result_image; //rgba output
@@ -3869,15 +3891,15 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
double image_metric_max, image_metric_mean, image_metric_mean_squared, image_metric_root_mean_squared, image_metric_peak_snr = 0.0;
const bool average_component_error = true;
- const uint32_t width = MIN(compared_image->get_width(), source_image->get_width());
- const uint32_t height = MIN(compared_image->get_height(), source_image->get_height());
+ const uint32_t w = MIN(compared_image->get_width(), source_image->get_width());
+ const uint32_t h = MIN(compared_image->get_height(), source_image->get_height());
// Histogram approach originally due to Charles Bloom.
double hist[256];
memset(hist, 0, sizeof(hist));
- for (uint32_t y = 0; y < height; y++) {
- for (uint32_t x = 0; x < width; x++) {
+ for (uint32_t y = 0; y < h; y++) {
+ for (uint32_t x = 0; x < w; x++) {
const Color color_a = compared_image->get_pixel(x, y);
const Color color_b = source_image->get_pixel(x, y);
@@ -3922,7 +3944,7 @@ Dictionary Image::compute_image_metrics(const Ref<Image> p_compared_image, bool
}
// See http://richg42.blogspot.com/2016/09/how-to-compute-psnr-from-old-berkeley.html
- double total_values = width * height;
+ double total_values = w * h;
if (average_component_error) {
total_values *= 4;
diff --git a/core/io/image.h b/core/io/image.h
index fd264a7a38..62df81e7c8 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -279,12 +279,12 @@ public:
void normalize(); //for normal maps
/**
- * Create a new image of a given size and format. Current image will be lost
+ * Creates new internal image data of a given size and format. Current image will be lost.
*/
- void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
- void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
+ void initialize_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void initialize_data(const char **p_xpm);
- void create(const char **p_xpm);
/**
* returns true when the image is empty (0,0) in size
*/
@@ -303,13 +303,9 @@ public:
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
- void create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
- create(p_width, p_height, p_use_mipmaps, p_format);
- }
-
- void create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
- create(p_width, p_height, p_use_mipmaps, p_format, p_data);
- }
+ static Ref<Image> create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
+ static Ref<Image> create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
+ void set_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
/**
* create an empty image
@@ -381,7 +377,7 @@ public:
void fill_rect(const Rect2i &p_rect, const Color &p_color);
Rect2i get_used_rect() const;
- Ref<Image> get_rect(const Rect2i &p_area) const;
+ Ref<Image> get_region(const Rect2i &p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels));
static void set_compress_bptc_func(void (*p_compress_func)(Image *, float, UsedChannels));
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index d09697b951..6c00ca4b67 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -32,6 +32,12 @@
#include "core/string/print_string.h"
+void ImageFormatLoader::_bind_methods() {
+ BIND_BITFIELD_FLAG(FLAG_NONE);
+ BIND_BITFIELD_FLAG(FLAG_FORCE_LINEAR);
+ BIND_BITFIELD_FLAG(FLAG_CONVERT_COLORS);
+}
+
bool ImageFormatLoader::recognize(const String &p_extension) const {
List<String> extensions;
get_recognized_extensions(&extensions);
@@ -44,7 +50,37 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
return false;
}
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) {
+Error ImageFormatLoaderExtension::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
+ Error err = ERR_UNAVAILABLE;
+ GDVIRTUAL_CALL(_load_image, p_image, p_fileaccess, p_flags, p_scale, err);
+ return err;
+}
+
+void ImageFormatLoaderExtension::get_recognized_extensions(List<String> *p_extension) const {
+ PackedStringArray ext;
+ if (GDVIRTUAL_CALL(_get_recognized_extensions, ext)) {
+ for (int i = 0; i < ext.size(); i++) {
+ p_extension->push_back(ext[i]);
+ }
+ }
+}
+
+void ImageFormatLoaderExtension::add_format_loader() {
+ ImageLoader::add_image_format_loader(this);
+}
+
+void ImageFormatLoaderExtension::remove_format_loader() {
+ ImageLoader::remove_image_format_loader(this);
+}
+
+void ImageFormatLoaderExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_load_image, "image", "fileaccess", "flags", "scale");
+ ClassDB::bind_method(D_METHOD("add_format_loader"), &ImageFormatLoaderExtension::add_format_loader);
+ ClassDB::bind_method(D_METHOD("remove_format_loader"), &ImageFormatLoaderExtension::remove_format_loader);
+}
+
+Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, BitField<ImageFormatLoader::LoaderFlags> p_flags, float p_scale) {
ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object.");
Ref<FileAccess> f = p_custom;
@@ -60,7 +96,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess>
if (!loader[i]->recognize(extension)) {
continue;
}
- Error err = loader[i]->load_image(p_image, f, p_flags, p_scale);
+ Error err = loader.write[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
ERR_PRINT("Error loading image: " + p_file);
}
@@ -79,7 +115,7 @@ void ImageLoader::get_recognized_extensions(List<String> *p_extensions) {
}
}
-ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
+Ref<ImageFormatLoader> ImageLoader::recognize(const String &p_extension) {
for (int i = 0; i < loader.size(); i++) {
if (loader[i]->recognize(p_extension)) {
return loader[i];
@@ -89,17 +125,17 @@ ImageFormatLoader *ImageLoader::recognize(const String &p_extension) {
return nullptr;
}
-Vector<ImageFormatLoader *> ImageLoader::loader;
+Vector<Ref<ImageFormatLoader>> ImageLoader::loader;
-void ImageLoader::add_image_format_loader(ImageFormatLoader *p_loader) {
+void ImageLoader::add_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.push_back(p_loader);
}
-void ImageLoader::remove_image_format_loader(ImageFormatLoader *p_loader) {
+void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.erase(p_loader);
}
-const Vector<ImageFormatLoader *> &ImageLoader::get_image_format_loaders() {
+const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() {
return loader;
}
@@ -152,7 +188,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::loader[idx]->load_image(image, f);
+ Error err = ImageLoader::loader.write[idx]->load_image(image, f);
if (err != OK) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index bf78005e40..f70fdf22aa 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -31,23 +31,23 @@
#ifndef IMAGE_LOADER_H
#define IMAGE_LOADER_H
+#include "core/core_bind.h"
#include "core/io/file_access.h"
#include "core/io/image.h"
#include "core/io/resource_loader.h"
+#include "core/object/gdvirtual.gen.inc"
#include "core/string/ustring.h"
#include "core/templates/list.h"
+#include "core/variant/binder_common.h"
class ImageLoader;
-class ImageFormatLoader {
+class ImageFormatLoader : public RefCounted {
+ GDCLASS(ImageFormatLoader, RefCounted);
+
friend class ImageLoader;
friend class ResourceFormatLoaderImage;
-protected:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0;
- virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
- bool recognize(const String &p_extension) const;
-
public:
enum LoaderFlags {
FLAG_NONE = 0,
@@ -55,23 +55,50 @@ public:
FLAG_CONVERT_COLORS = 2,
};
+protected:
+ static void _bind_methods();
+
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) = 0;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
+ bool recognize(const String &p_extension) const;
+
+public:
virtual ~ImageFormatLoader() {}
};
+VARIANT_BITFIELD_CAST(ImageFormatLoader::LoaderFlags);
+
+class ImageFormatLoaderExtension : public ImageFormatLoader {
+ GDCLASS(ImageFormatLoaderExtension, ImageFormatLoader);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, BitField<ImageFormatLoader::LoaderFlags> p_flags = FLAG_NONE, float p_scale = 1.0) override;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
+
+ void add_format_loader();
+ void remove_format_loader();
+
+ GDVIRTUAL0RC(PackedStringArray, _get_recognized_extensions);
+ GDVIRTUAL4R(Error, _load_image, Ref<Image>, Ref<FileAccess>, BitField<ImageFormatLoader::LoaderFlags>, float);
+};
+
class ImageLoader {
- static Vector<ImageFormatLoader *> loader;
+ static Vector<Ref<ImageFormatLoader>> loader;
friend class ResourceFormatLoaderImage;
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
+ static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), BitField<ImageFormatLoader::LoaderFlags> p_flags = ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
- static ImageFormatLoader *recognize(const String &p_extension);
+ static Ref<ImageFormatLoader> recognize(const String &p_extension);
- static void add_image_format_loader(ImageFormatLoader *p_loader);
- static void remove_image_format_loader(ImageFormatLoader *p_loader);
+ static void add_image_format_loader(Ref<ImageFormatLoader> p_loader);
+ static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader);
- static const Vector<ImageFormatLoader *> &get_image_format_loaders();
+ static const Vector<Ref<ImageFormatLoader>> &get_image_format_loaders();
static void cleanup();
};
diff --git a/core/io/json.cpp b/core/io/json.cpp
index a685fcb718..7e267d35d4 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -56,6 +56,8 @@ String JSON::_make_indent(const String &p_indent, int p_size) {
}
String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision) {
+ ERR_FAIL_COND_V_MSG(p_cur_indent > Variant::MAX_RECURSION_DEPTH, "...", "JSON structure is too deep. Bailing.");
+
String colon = ":";
String end_statement = "";
@@ -357,17 +359,22 @@ Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_to
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
+ if (p_depth > Variant::MAX_RECURSION_DEPTH) {
+ r_err_str = "JSON structure is too deep. Bailing.";
+ return ERR_OUT_OF_MEMORY;
+ }
+
if (token.type == TK_CURLY_BRACKET_OPEN) {
Dictionary d;
- Error err = _parse_object(d, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_object(d, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
value = d;
} else if (token.type == TK_BRACKET_OPEN) {
Array a;
- Error err = _parse_array(a, p_str, index, p_len, line, r_err_str);
+ Error err = _parse_array(a, p_str, index, p_len, line, p_depth + 1, r_err_str);
if (err) {
return err;
}
@@ -396,7 +403,7 @@ Error JSON::_parse_value(Variant &value, Token &token, const char32_t *p_str, in
return OK;
}
-Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
Token token;
bool need_comma = false;
@@ -421,7 +428,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -434,7 +441,7 @@ Error JSON::_parse_array(Array &array, const char32_t *p_str, int &index, int p_
return ERR_PARSE_ERROR;
}
-Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str) {
+Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str) {
bool at_key = true;
String key;
Token token;
@@ -483,7 +490,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
}
Variant v;
- err = _parse_value(v, token, p_str, index, p_len, line, r_err_str);
+ err = _parse_value(v, token, p_str, index, p_len, line, p_depth, r_err_str);
if (err) {
return err;
}
@@ -514,7 +521,7 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
return err;
}
- err = _parse_value(r_ret, token, str, idx, len, r_err_line, r_err_str);
+ err = _parse_value(r_ret, token, str, idx, len, r_err_line, 0, r_err_str);
// Check if EOF is reached
// or it's a type of the next token.
diff --git a/core/io/json.h b/core/io/json.h
index 208d4ad625..829a5f922b 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -74,9 +74,9 @@ class JSON : public RefCounted {
static String _make_indent(const String &p_indent, int p_size);
static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, HashSet<const void *> &p_markers, bool p_full_precision = false);
static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str);
- static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
- static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str);
+ static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
+ static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, int p_depth, String &r_err_str);
static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line);
protected:
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index b0f74f8db5..288e53d075 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -87,7 +87,7 @@ void Logger::log_error(const char *p_function, const char *p_file, int p_line, c
} else {
logf_error("USER %s: %s\n", err_type, err_details);
}
- logf_error(" at: %s (%s:%i) - %s\n", p_function, p_file, p_line, p_code);
+ logf_error(" at: %s (%s:%i)\n", p_function, p_file, p_line);
}
void Logger::logf(const char *p_format, ...) {
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index b24c49f58d..9ba653e1a9 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -503,7 +503,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(double) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- val.matrix[i][j] = decode_double(&buf[(i * 4 + j) * sizeof(double)]);
+ val.columns[i][j] = decode_double(&buf[(i * 4 + j) * sizeof(double)]);
}
}
if (r_len) {
@@ -513,7 +513,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
ERR_FAIL_COND_V((size_t)len < sizeof(float) * 16, ERR_INVALID_DATA);
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- val.matrix[i][j] = decode_float(&buf[(i * 4 + j) * sizeof(float)]);
+ val.columns[i][j] = decode_float(&buf[(i * 4 + j) * sizeof(float)]);
}
}
@@ -1450,7 +1450,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
Projection val = p_variant;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- memcpy(&buf[(i * 4 + j) * sizeof(real_t)], &val.matrix[i][j], sizeof(real_t));
+ memcpy(&buf[(i * 4 + j) * sizeof(real_t)], &val.columns[i][j], sizeof(real_t));
}
}
}
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 553698f8a6..ab30fb1ca3 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -489,7 +489,7 @@ bool ResourceCache::has(const String &p_path) {
Resource **res = resources.getptr(p_path);
- if (res && (*res)->reference_get_count() == 0) {
+ if (res && (*res)->get_reference_count() == 0) {
// This resource is in the process of being deleted, ignore its existence.
(*res)->path_cache = String();
resources.erase(p_path);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 4f1204fc48..4611528db7 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -107,7 +107,7 @@ void ResourceLoaderBinary::_advance_padding(uint32_t p_len) {
static Error read_reals(real_t *dst, Ref<FileAccess> &f, size_t count) {
if (f->real_is_double) {
- if (sizeof(real_t) == 8) {
+ if constexpr (sizeof(real_t) == 8) {
// Ideal case with double-precision
f->get_buffer((uint8_t *)dst, count * sizeof(double));
#ifdef BIG_ENDIAN_ENABLED
@@ -118,7 +118,7 @@ static Error read_reals(real_t *dst, Ref<FileAccess> &f, size_t count) {
}
}
#endif
- } else if (sizeof(real_t) == 4) {
+ } else if constexpr (sizeof(real_t) == 4) {
// May be slower, but this is for compatibility. Eventually the data should be converted.
for (size_t i = 0; i < count; ++i) {
dst[i] = f->get_double();
@@ -127,7 +127,7 @@ static Error read_reals(real_t *dst, Ref<FileAccess> &f, size_t count) {
ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "real_t size is neither 4 nor 8!");
}
} else {
- if (sizeof(real_t) == 4) {
+ if constexpr (sizeof(real_t) == 4) {
// Ideal case with float-precision
f->get_buffer((uint8_t *)dst, count * sizeof(float));
#ifdef BIG_ENDIAN_ENABLED
@@ -138,7 +138,7 @@ static Error read_reals(real_t *dst, Ref<FileAccess> &f, size_t count) {
}
}
#endif
- } else if (sizeof(real_t) == 8) {
+ } else if constexpr (sizeof(real_t) == 8) {
for (size_t i = 0; i < count; ++i) {
dst[i] = f->get_float();
}
@@ -169,10 +169,10 @@ StringName ResourceLoaderBinary::_get_string() {
}
Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
- uint32_t type = f->get_32();
- print_bl("find property of type: " + itos(type));
+ uint32_t prop_type = f->get_32();
+ print_bl("find property of type: " + itos(prop_type));
- switch (type) {
+ switch (prop_type) {
case VARIANT_NIL: {
r_v = Variant();
} break;
@@ -327,22 +327,22 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
} break;
case VARIANT_PROJECTION: {
Projection v;
- v.matrix[0].x = f->get_real();
- v.matrix[0].y = f->get_real();
- v.matrix[0].z = f->get_real();
- v.matrix[0].w = f->get_real();
- v.matrix[1].x = f->get_real();
- v.matrix[1].y = f->get_real();
- v.matrix[1].z = f->get_real();
- v.matrix[1].w = f->get_real();
- v.matrix[2].x = f->get_real();
- v.matrix[2].y = f->get_real();
- v.matrix[2].z = f->get_real();
- v.matrix[2].w = f->get_real();
- v.matrix[3].x = f->get_real();
- v.matrix[3].y = f->get_real();
- v.matrix[3].z = f->get_real();
- v.matrix[3].w = f->get_real();
+ v.columns[0].x = f->get_real();
+ v.columns[0].y = f->get_real();
+ v.columns[0].z = f->get_real();
+ v.columns[0].w = f->get_real();
+ v.columns[1].x = f->get_real();
+ v.columns[1].y = f->get_real();
+ v.columns[1].z = f->get_real();
+ v.columns[1].w = f->get_real();
+ v.columns[2].x = f->get_real();
+ v.columns[2].y = f->get_real();
+ v.columns[2].z = f->get_real();
+ v.columns[2].w = f->get_real();
+ v.columns[3].x = f->get_real();
+ v.columns[3].y = f->get_real();
+ v.columns[3].z = f->get_real();
+ v.columns[3].w = f->get_real();
r_v = v;
} break;
case VARIANT_COLOR: {
@@ -1042,7 +1042,14 @@ void ResourceLoaderBinary::open(Ref<FileAccess> p_f, bool p_no_resources, bool p
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
er.path = ResourceUID::get_singleton()->get_id_path(er.uid);
} else {
+#ifdef TOOLS_ENABLED
+ // Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
+ if (ResourceLoader::get_resource_uid(res_path) != er.uid) {
+ WARN_PRINT(String(res_path + ": In external resource #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data());
+ }
+#else
WARN_PRINT(String(res_path + ": In external resource #" + itos(i) + ", invalid UUID: " + ResourceUID::get_singleton()->id_to_text(er.uid) + " - using text path instead: " + er.path).utf8().get_data());
+#endif
}
}
}
@@ -1100,16 +1107,14 @@ String ResourceLoaderBinary::recognize(Ref<FileAccess> p_f) {
uint32_t ver_major = f->get_32();
f->get_32(); // ver_minor
- uint32_t ver_format = f->get_32();
+ uint32_t ver_fmt = f->get_32();
- if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
+ if (ver_fmt > FORMAT_VERSION || ver_major > VERSION_MAJOR) {
f.unref();
return "";
}
- String type = get_unicode_string();
-
- return type;
+ return get_unicode_string();
}
Ref<Resource> 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) {
@@ -1206,7 +1211,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
Ref<FileAccessCompressed> facw;
facw.instantiate();
facw->configure("RSCC");
- err = facw->_open(p_path + ".depren", FileAccess::WRITE);
+ err = facw->open_internal(p_path + ".depren", FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(err, ERR_FILE_CORRUPT, "Cannot create file '" + p_path + ".depren'.");
fw = facw;
@@ -1630,22 +1635,22 @@ void ResourceFormatSaverBinaryInstance::write_variant(Ref<FileAccess> f, const V
case Variant::PROJECTION: {
f->store_32(VARIANT_PROJECTION);
Projection val = p_property;
- f->store_real(val.matrix[0].x);
- f->store_real(val.matrix[0].y);
- f->store_real(val.matrix[0].z);
- f->store_real(val.matrix[0].w);
- f->store_real(val.matrix[1].x);
- f->store_real(val.matrix[1].y);
- f->store_real(val.matrix[1].z);
- f->store_real(val.matrix[1].w);
- f->store_real(val.matrix[2].x);
- f->store_real(val.matrix[2].y);
- f->store_real(val.matrix[2].z);
- f->store_real(val.matrix[2].w);
- f->store_real(val.matrix[3].x);
- f->store_real(val.matrix[3].y);
- f->store_real(val.matrix[3].z);
- f->store_real(val.matrix[3].w);
+ f->store_real(val.columns[0].x);
+ f->store_real(val.columns[0].y);
+ f->store_real(val.columns[0].z);
+ f->store_real(val.columns[0].w);
+ f->store_real(val.columns[1].x);
+ f->store_real(val.columns[1].y);
+ f->store_real(val.columns[1].z);
+ f->store_real(val.columns[1].w);
+ f->store_real(val.columns[2].x);
+ f->store_real(val.columns[2].y);
+ f->store_real(val.columns[2].z);
+ f->store_real(val.columns[2].w);
+ f->store_real(val.columns[3].x);
+ f->store_real(val.columns[3].y);
+ f->store_real(val.columns[3].z);
+ f->store_real(val.columns[3].w);
} break;
case Variant::COLOR: {
@@ -1986,7 +1991,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
fac.instantiate();
fac->configure("RSCC");
f = fac;
- err = fac->_open(p_path, FileAccess::WRITE);
+ err = fac->open_internal(p_path, FileAccess::WRITE);
} else {
f = FileAccess::open(p_path, FileAccess::WRITE, &err);
}
@@ -2118,9 +2123,9 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Re
for (int i = 0; i < save_order.size(); i++) {
save_unicode_string(f, save_order[i]->get_save_class());
- String path = save_order[i]->get_path();
- path = relative_paths ? local_path.path_to_file(path) : path;
- save_unicode_string(f, path);
+ String res_path = save_order[i]->get_path();
+ res_path = relative_paths ? local_path.path_to_file(res_path) : res_path;
+ save_unicode_string(f, res_path);
ResourceUID::ID ruid = ResourceSaver::get_resource_id_for_path(save_order[i]->get_path(), false);
f->store_64(ruid);
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index d923522317..564b37e662 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -110,8 +110,8 @@ Error ResourceFormatImporter::_get_path_and_type(const String &p_path, PathAndTy
#ifdef TOOLS_ENABLED
if (r_path_and_type.metadata && !r_path_and_type.path.is_empty()) {
- Dictionary metadata = r_path_and_type.metadata;
- if (metadata.has("has_editor_variant")) {
+ Dictionary meta = r_path_and_type.metadata;
+ if (meta.has("has_editor_variant")) {
r_path_and_type.path = r_path_and_type.path.get_basename() + ".editor." + r_path_and_type.path.get_extension();
}
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index eccb397e2e..6219ea70e4 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -49,6 +49,11 @@ Ref<ResourceFormatLoader> ResourceLoader::loader[ResourceLoader::MAX_LOADERS];
int ResourceLoader::loader_count = 0;
bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_for_type) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_recognize_path, p_path, p_for_type, ret)) {
+ return ret;
+ }
+
String extension = p_path.get_extension();
List<String> extensions;
@@ -68,12 +73,9 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_
}
bool ResourceFormatLoader::handles_type(const String &p_type) const {
- bool success;
- if (GDVIRTUAL_CALL(_handles_type, p_type, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_handles_type, p_type, success);
+ return success;
}
void ResourceFormatLoader::get_classes_used(const String &p_path, HashSet<StringName> *r_classes) {
@@ -93,21 +95,14 @@ void ResourceFormatLoader::get_classes_used(const String &p_path, HashSet<String
String ResourceFormatLoader::get_resource_type(const String &p_path) const {
String ret;
-
- if (GDVIRTUAL_CALL(_get_resource_type, p_path, ret)) {
- return ret;
- }
-
- return "";
+ GDVIRTUAL_CALL(_get_resource_type, p_path, ret);
+ return ret;
}
ResourceUID::ID ResourceFormatLoader::get_resource_uid(const String &p_path) const {
- int64_t uid;
- if (GDVIRTUAL_CALL(_get_resource_uid, p_path, uid)) {
- return uid;
- }
-
- return ResourceUID::INVALID_ID;
+ int64_t uid = ResourceUID::INVALID_ID;
+ GDVIRTUAL_CALL(_get_resource_uid, p_path, uid);
+ return uid;
}
void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const {
@@ -123,11 +118,11 @@ void ResourceLoader::get_recognized_extensions_for_type(const String &p_type, Li
}
bool ResourceFormatLoader::exists(const String &p_path) const {
- bool success;
+ bool success = false;
if (GDVIRTUAL_CALL(_exists, p_path, success)) {
return success;
}
- return FileAccess::exists(p_path); //by default just check file
+ return FileAccess::exists(p_path); // By default just check file.
}
void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const {
@@ -175,12 +170,9 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Hash
deps_dict[E.key] = E.value;
}
- int64_t err;
- if (GDVIRTUAL_CALL(_rename_dependencies, p_path, deps_dict, err)) {
- return (Error)err;
- }
-
- return OK;
+ int64_t err = OK;
+ GDVIRTUAL_CALL(_rename_dependencies, p_path, deps_dict, err);
+ return (Error)err;
}
void ResourceFormatLoader::_bind_methods() {
@@ -189,6 +181,7 @@ void ResourceFormatLoader::_bind_methods() {
BIND_ENUM_CONSTANT(CACHE_MODE_REPLACE);
GDVIRTUAL_BIND(_get_recognized_extensions);
+ GDVIRTUAL_BIND(_recognize_path, "path", "type");
GDVIRTUAL_BIND(_handles_type, "type");
GDVIRTUAL_BIND(_get_resource_type, "path");
GDVIRTUAL_BIND(_get_resource_uid, "path");
@@ -908,7 +901,7 @@ void ResourceLoader::load_translation_remaps() {
return;
}
- Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
List<Variant> keys;
remaps.get_key_list(&keys);
for (const Variant &E : keys) {
@@ -935,7 +928,7 @@ void ResourceLoader::load_path_remaps() {
return;
}
- Vector<String> remaps = ProjectSettings::get_singleton()->get("path_remap/remapped_paths");
+ Vector<String> remaps = GLOBAL_GET("path_remap/remapped_paths");
int rc = remaps.size();
ERR_FAIL_COND(rc & 1); //must be even
const String *r = remaps.ptr();
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 91ba930176..243670b2d0 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -51,6 +51,7 @@ protected:
static void _bind_methods();
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
+ GDVIRTUAL2RC(bool, _recognize_path, String, StringName)
GDVIRTUAL1RC(bool, _handles_type, StringName)
GDVIRTUAL1RC(String, _get_resource_type, String)
GDVIRTUAL1RC(ResourceUID::ID, _get_resource_uid, String)
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 386ccb78e9..710afc614f 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -42,21 +42,15 @@ ResourceSavedCallback ResourceSaver::save_callback = nullptr;
ResourceSaverGetResourceIDForPath ResourceSaver::save_get_id_for_path = nullptr;
Error ResourceFormatSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
- int64_t res;
- if (GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res)) {
- return (Error)res;
- }
-
- return ERR_METHOD_NOT_FOUND;
+ int64_t res = ERR_METHOD_NOT_FOUND;
+ GDVIRTUAL_CALL(_save, p_resource, p_path, p_flags, res);
+ return (Error)res;
}
bool ResourceFormatSaver::recognize(const Ref<Resource> &p_resource) const {
- bool success;
- if (GDVIRTUAL_CALL(_recognize, p_resource, success)) {
- return success;
- }
-
- return false;
+ bool success = false;
+ GDVIRTUAL_CALL(_recognize, p_resource, success);
+ return success;
}
void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
@@ -69,10 +63,31 @@ void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resou
}
}
+bool ResourceFormatSaver::recognize_path(const Ref<Resource> &p_resource, const String &p_path) const {
+ bool ret = false;
+ if (GDVIRTUAL_CALL(_recognize_path, p_resource, p_path, ret)) {
+ return ret;
+ }
+
+ String extension = p_path.get_extension();
+
+ List<String> extensions;
+ get_recognized_extensions(p_resource, &extensions);
+
+ for (const String &E : extensions) {
+ if (E.nocasecmp_to(extension) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void ResourceFormatSaver::_bind_methods() {
GDVIRTUAL_BIND(_save, "resource", "path", "flags");
GDVIRTUAL_BIND(_recognize, "resource");
GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
+ GDVIRTUAL_BIND(_recognize_path, "resource", "path");
}
Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
@@ -90,17 +105,7 @@ Error ResourceSaver::save(const Ref<Resource> &p_resource, const String &p_path,
continue;
}
- List<String> extensions;
- bool recognized = false;
- saver[i]->get_recognized_extensions(p_resource, &extensions);
-
- for (const String &E : extensions) {
- if (E.nocasecmp_to(extension) == 0) {
- recognized = true;
- }
- }
-
- if (!recognized) {
+ if (!saver[i]->recognize_path(p_resource, path)) {
continue;
}
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 4fee2bcfd1..5e48ce88c3 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -44,11 +44,13 @@ protected:
GDVIRTUAL3R(int64_t, _save, Ref<Resource>, String, uint32_t)
GDVIRTUAL1RC(bool, _recognize, Ref<Resource>)
GDVIRTUAL1RC(Vector<String>, _get_recognized_extensions, Ref<Resource>)
+ GDVIRTUAL2RC(bool, _recognize_path, Ref<Resource>, String)
public:
virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
virtual bool recognize(const Ref<Resource> &p_resource) const;
virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize_path(const Ref<Resource> &p_resource, const String &p_path) const;
virtual ~ResourceFormatSaver() {}
};
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index 5324c5dd84..ed5ce3b911 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -113,7 +113,12 @@ void ResourceUID::set_id(ID p_id, const String &p_path) {
MutexLock l(mutex);
ERR_FAIL_COND(!unique_ids.has(p_id));
CharString cs = p_path.utf8();
- if (strcmp(cs.ptr(), unique_ids[p_id].cs.ptr()) != 0) {
+ const char *update_ptr = cs.ptr();
+ const char *cached_ptr = unique_ids[p_id].cs.ptr();
+ if (update_ptr == nullptr && cached_ptr == nullptr) {
+ return; // Both are empty strings.
+ }
+ if ((update_ptr == nullptr) != (cached_ptr == nullptr) || strcmp(update_ptr, cached_ptr) != 0) {
unique_ids[p_id].cs = cs;
unique_ids[p_id].saved_to_cache = false; //changed
changed = true;
diff --git a/core/io/stream_peer_gzip.cpp b/core/io/stream_peer_gzip.cpp
new file mode 100644
index 0000000000..ca8be2d62e
--- /dev/null
+++ b/core/io/stream_peer_gzip.cpp
@@ -0,0 +1,209 @@
+/*************************************************************************/
+/* stream_peer_gzip.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core/io/stream_peer_gzip.h"
+
+#include "core/io/zip_io.h"
+#include <zlib.h>
+
+void StreamPeerGZIP::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("start_compression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_compression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("start_decompression", "use_deflate", "buffer_size"), &StreamPeerGZIP::start_decompression, DEFVAL(false), DEFVAL(65535));
+ ClassDB::bind_method(D_METHOD("finish"), &StreamPeerGZIP::finish);
+ ClassDB::bind_method(D_METHOD("clear"), &StreamPeerGZIP::clear);
+}
+
+StreamPeerGZIP::StreamPeerGZIP() {
+}
+
+StreamPeerGZIP::~StreamPeerGZIP() {
+ _close();
+}
+
+void StreamPeerGZIP::_close() {
+ if (ctx) {
+ z_stream *strm = (z_stream *)ctx;
+ if (compressing) {
+ deflateEnd(strm);
+ } else {
+ inflateEnd(strm);
+ }
+ memfree(strm);
+ ctx = nullptr;
+ }
+}
+
+void StreamPeerGZIP::clear() {
+ _close();
+ rb.clear();
+ buffer.clear();
+}
+
+Error StreamPeerGZIP::start_compression(bool p_is_deflate, int buffer_size) {
+ return _start(true, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::start_decompression(bool p_is_deflate, int buffer_size) {
+ return _start(false, p_is_deflate, buffer_size);
+}
+
+Error StreamPeerGZIP::_start(bool p_compress, bool p_is_deflate, int buffer_size) {
+ ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
+ clear();
+ compressing = p_compress;
+ rb.resize(nearest_shift(buffer_size - 1));
+ buffer.resize(1024);
+
+ // Create ctx.
+ ctx = memalloc(sizeof(z_stream));
+ z_stream &strm = *(z_stream *)ctx;
+ strm.next_in = Z_NULL;
+ strm.avail_in = 0;
+ strm.zalloc = zipio_alloc;
+ strm.zfree = zipio_free;
+ strm.opaque = Z_NULL;
+ int window_bits = p_is_deflate ? 15 : (15 + 16);
+ int err = Z_OK;
+ int level = Z_DEFAULT_COMPRESSION;
+ if (compressing) {
+ err = deflateInit2(&strm, level, Z_DEFLATED, window_bits, 8, Z_DEFAULT_STRATEGY);
+ } else {
+ err = inflateInit2(&strm, window_bits);
+ }
+ ERR_FAIL_COND_V(err != Z_OK, FAILED);
+ return OK;
+}
+
+Error StreamPeerGZIP::_process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ z_stream &strm = *(z_stream *)ctx;
+ strm.avail_in = p_src_size;
+ strm.avail_out = p_dst_size;
+ strm.next_in = (Bytef *)p_src;
+ strm.next_out = (Bytef *)p_dst;
+ int flush = p_close ? Z_FINISH : Z_NO_FLUSH;
+ if (compressing) {
+ int err = deflate(&strm, flush);
+ ERR_FAIL_COND_V(err != (p_close ? Z_STREAM_END : Z_OK), FAILED);
+ } else {
+ int err = inflate(&strm, flush);
+ ERR_FAIL_COND_V(err != Z_OK && err != Z_STREAM_END, FAILED);
+ }
+ r_out = p_dst_size - strm.avail_out;
+ r_consumed = p_src_size - strm.avail_in;
+ return OK;
+}
+
+Error StreamPeerGZIP::put_data(const uint8_t *p_data, int p_bytes) {
+ int wrote = 0;
+ Error err = put_partial_data(p_data, p_bytes, wrote);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != wrote, ERR_OUT_OF_MEMORY);
+ return OK;
+}
+
+Error StreamPeerGZIP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
+ ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < p_bytes) {
+ buffer.resize(p_bytes);
+ }
+
+ r_sent = 0;
+ while (r_sent < p_bytes && rb.space_left() > 1024) { // Keep the ring buffer size meaningful.
+ int sent = 0;
+ int to_write = 0;
+ // Compress or decompress
+ Error err = _process(buffer.ptrw(), MIN(buffer.size(), rb.space_left()), p_data + r_sent, p_bytes - r_sent, sent, to_write);
+ if (err != OK) {
+ return err;
+ }
+ // When decompressing, we might need to do another round.
+ r_sent += sent;
+
+ // We can't write more than this buffer is full.
+ if (sent == 0 && to_write == 0) {
+ return OK;
+ }
+ if (to_write) {
+ // Copy to ring buffer.
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_BUG);
+ }
+ }
+ return OK;
+}
+
+Error StreamPeerGZIP::get_data(uint8_t *p_buffer, int p_bytes) {
+ int received = 0;
+ Error err = get_partial_data(p_buffer, p_bytes, received);
+ if (err != OK) {
+ return err;
+ }
+ ERR_FAIL_COND_V(p_bytes != received, ERR_UNAVAILABLE);
+ return OK;
+}
+
+Error StreamPeerGZIP::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
+ ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
+
+ r_received = MIN(p_bytes, rb.data_left());
+ if (r_received == 0) {
+ return OK;
+ }
+ int received = rb.read(p_buffer, r_received);
+ ERR_FAIL_COND_V(received != r_received, ERR_BUG);
+ return OK;
+}
+
+int StreamPeerGZIP::get_available_bytes() const {
+ return rb.data_left();
+}
+
+Error StreamPeerGZIP::finish() {
+ ERR_FAIL_COND_V(!ctx || !compressing, ERR_UNAVAILABLE);
+ // Ensure we have enough space in temporary buffer.
+ if (buffer.size() < 1024) {
+ buffer.resize(1024); // 1024 should be more than enough.
+ }
+ int consumed = 0;
+ int to_write = 0;
+ Error err = _process(buffer.ptrw(), 1024, nullptr, 0, consumed, to_write, true); // compress
+ if (err != OK) {
+ return err;
+ }
+ int wrote = rb.write(buffer.ptr(), to_write);
+ ERR_FAIL_COND_V(wrote != to_write, ERR_OUT_OF_MEMORY);
+ return OK;
+}
diff --git a/core/io/stream_peer_gzip.h b/core/io/stream_peer_gzip.h
new file mode 100644
index 0000000000..5bafdbca9b
--- /dev/null
+++ b/core/io/stream_peer_gzip.h
@@ -0,0 +1,76 @@
+/*************************************************************************/
+/* stream_peer_gzip.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef STREAM_PEER_GZIP_H
+#define STREAM_PEER_GZIP_H
+
+#include "core/io/stream_peer.h"
+
+#include "core/core_bind.h"
+#include "core/io/compression.h"
+#include "core/templates/ring_buffer.h"
+
+class StreamPeerGZIP : public StreamPeer {
+ GDCLASS(StreamPeerGZIP, StreamPeer);
+
+private:
+ void *ctx = nullptr; // Will hold our z_stream instance.
+ bool compressing = true;
+
+ RingBuffer<uint8_t> rb;
+ Vector<uint8_t> buffer;
+
+ Error _process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close = false);
+ void _close();
+ Error _start(bool p_compress, bool p_is_deflate, int buffer_size = 65535);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error start_compression(bool p_is_deflate, int buffer_size = 65535);
+ Error start_decompression(bool p_is_deflate, int buffer_size = 65535);
+
+ Error finish();
+ void clear();
+
+ virtual Error put_data(const uint8_t *p_data, int p_bytes) override;
+ virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
+
+ virtual Error get_data(uint8_t *p_buffer, int p_bytes) override;
+ virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
+
+ virtual int get_available_bytes() const override;
+
+ StreamPeerGZIP();
+ ~StreamPeerGZIP();
+};
+
+#endif // STREAM_PEER_GZIP_H
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index ba79590c19..e035e1b613 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -256,9 +256,9 @@ void StreamPeerTCP::disconnect_from_host() {
peer_port = 0;
}
-Error StreamPeerTCP::wait(NetSocket::PollType p_type, int timeout) {
+Error StreamPeerTCP::wait(NetSocket::PollType p_type, int p_timeout) {
ERR_FAIL_COND_V(_sock.is_null() || !_sock->is_open(), ERR_UNAVAILABLE);
- return _sock->poll(p_type, timeout);
+ return _sock->poll(p_type, p_timeout);
}
Error StreamPeerTCP::put_data(const uint8_t *p_data, int p_bytes) {
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 39c2e84346..778fb83374 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -79,7 +79,7 @@ public:
Error poll();
// Wait or check for writable, readable.
- Error wait(NetSocket::PollType p_type, int timeout = 0);
+ Error wait(NetSocket::PollType p_type, int p_timeout = 0);
// Read/Write from StreamPeer
Error put_data(const uint8_t *p_data, int p_bytes) override;
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index abae48fdd8..16b7f3a1f6 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -41,11 +41,11 @@ static inline bool _is_white_space(char c) {
}
//! sets the state that text was found. Returns true if set should be set
-bool XMLParser::_set_text(char *start, char *end) {
+bool XMLParser::_set_text(const char *start, const char *end) {
// check if text is more than 2 characters, and if not, check if there is
// only white space, so that this text won't be reported
if (end - start < 3) {
- char *p = start;
+ const char *p = start;
for (; p != end; ++p) {
if (!_is_white_space(*p)) {
break;
@@ -92,7 +92,7 @@ void XMLParser::_parse_closing_xml_element() {
void XMLParser::_ignore_definition() {
node_type = NODE_UNKNOWN;
- char *F = P;
+ const char *F = P;
// move until end marked with '>' reached
while (*P && *P != '>') {
next_char();
@@ -123,8 +123,8 @@ bool XMLParser::_parse_cdata() {
return true;
}
- char *cDataBegin = P;
- char *cDataEnd = nullptr;
+ const char *cDataBegin = P;
+ const char *cDataEnd = nullptr;
// find end of CDATA
while (*P && !cDataEnd) {
@@ -152,9 +152,9 @@ void XMLParser::_parse_comment() {
node_type = NODE_COMMENT;
P += 1;
- char *pEndOfInput = data + length;
- char *pCommentBegin;
- char *pCommentEnd;
+ const char *pEndOfInput = data + length;
+ const char *pCommentBegin;
+ const char *pCommentEnd;
if (P + 1 < pEndOfInput && P[0] == '-' && P[1] == '-') {
// Comment, use '-->' as end.
@@ -293,7 +293,7 @@ void XMLParser::_parse_opening_xml_element() {
}
void XMLParser::_parse_current_node() {
- char *start = P;
+ const char *start = P;
node_offset = P - data;
// more forward until '<' found
@@ -458,15 +458,36 @@ bool XMLParser::is_empty() const {
Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) {
ERR_FAIL_COND_V(p_buffer.size() == 0, ERR_INVALID_DATA);
- if (data) {
- memdelete_arr(data);
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
}
length = p_buffer.size();
- data = memnew_arr(char, length + 1);
- memcpy(data, p_buffer.ptr(), length);
- data[length] = 0;
+ data_copy = memnew_arr(char, length + 1);
+ memcpy(data_copy, p_buffer.ptr(), length);
+ data_copy[length] = 0;
+ data = data_copy;
+ P = data;
+ current_line = 0;
+
+ return OK;
+}
+
+Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) {
+ ERR_FAIL_COND_V(p_size == 0, ERR_INVALID_DATA);
+ ERR_FAIL_COND_V(!p_buffer, ERR_INVALID_DATA);
+
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
+ }
+
+ length = p_size;
+ data = (const char *)p_buffer;
P = data;
+ current_line = 0;
+
return OK;
}
@@ -479,13 +500,15 @@ Error XMLParser::open(const String &p_path) {
length = file->get_length();
ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT);
- if (data) {
- memdelete_arr(data);
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
}
- data = memnew_arr(char, length + 1);
- file->get_buffer((uint8_t *)data, length);
- data[length] = 0;
+ data_copy = memnew_arr(char, length + 1);
+ file->get_buffer((uint8_t *)data_copy, length);
+ data_copy[length] = 0;
+ data = data_copy;
P = data;
current_line = 0;
@@ -512,8 +535,9 @@ void XMLParser::skip_section() {
}
void XMLParser::close() {
- if (data) {
+ if (data_copy) {
memdelete_arr(data);
+ data_copy = nullptr;
}
data = nullptr;
length = 0;
@@ -528,7 +552,8 @@ int XMLParser::get_current_line() const {
}
XMLParser::~XMLParser() {
- if (data) {
- memdelete_arr(data);
+ if (data_copy) {
+ memdelete_arr(data_copy);
+ data_copy = nullptr;
}
}
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index aea252ddc7..be44f771dc 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -65,8 +65,9 @@ public:
};
private:
- char *data = nullptr;
- char *P = nullptr;
+ char *data_copy = nullptr;
+ const char *data = nullptr;
+ const char *P = nullptr;
uint64_t length = 0;
uint64_t current_line = 0;
String node_name;
@@ -81,7 +82,7 @@ private:
Vector<Attribute> attributes;
- bool _set_text(char *start, char *end);
+ bool _set_text(const char *start, const char *end);
void _parse_closing_xml_element();
void _ignore_definition();
bool _parse_cdata();
@@ -118,6 +119,7 @@ public:
Error open(const String &p_path);
Error open_buffer(const Vector<uint8_t> &p_buffer);
+ Error _open_buffer(const uint8_t *p_buffer, size_t p_size);
void close();
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index e573e8de19..200e5f5e83 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -37,11 +37,17 @@ void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
String fname;
fname.parse_utf8(p_fname);
+ int file_access_mode = 0;
if (mode & ZLIB_FILEFUNC_MODE_WRITE) {
- (*fa) = FileAccess::open(fname, FileAccess::WRITE);
- } else {
- (*fa) = FileAccess::open(fname, FileAccess::READ);
+ file_access_mode |= FileAccess::WRITE;
}
+ if (mode & ZLIB_FILEFUNC_MODE_READ) {
+ file_access_mode |= FileAccess::READ;
+ }
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
+ file_access_mode |= FileAccess::WRITE_READ;
+ }
+ (*fa) = FileAccess::open(fname, file_access_mode);
if (fa->is_null()) {
return nullptr;
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index ad67cfa852..c30acf32bb 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -30,6 +30,8 @@
#include "a_star_grid_2d.h"
+#include "core/variant/typed_array.h"
+
static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
real_t dx = (real_t)ABS(p_to.x - p_from.x);
real_t dy = (real_t)ABS(p_to.y - p_from.y);
@@ -492,17 +494,17 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
return path;
}
-Vector<Vector2> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
- ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method.");
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
+ ERR_FAIL_COND_V_MSG(dirty, TypedArray<Vector2i>(), "Grid is not initialized. Call the update method.");
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
Point *a = _get_point(p_from_id.x, p_from_id.y);
Point *b = _get_point(p_to_id.x, p_to_id.y);
if (a == b) {
- Vector<Vector2> ret;
- ret.push_back(Vector2((float)a->id.x, (float)a->id.y));
+ TypedArray<Vector2i> ret;
+ ret.push_back(a);
return ret;
}
@@ -511,7 +513,7 @@ Vector<Vector2> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector
bool found_route = _solve(begin_point, end_point);
if (!found_route) {
- return Vector<Vector2>();
+ return TypedArray<Vector2i>();
}
Point *p = end_point;
@@ -521,20 +523,18 @@ Vector<Vector2> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector
p = p->prev_point;
}
- Vector<Vector2> path;
+ TypedArray<Vector2i> path;
path.resize(pc);
{
- Vector2 *w = path.ptrw();
-
p = end_point;
int64_t idx = pc - 1;
while (p != begin_point) {
- w[idx--] = Vector2((float)p->id.x, (float)p->id.y);
+ path[idx--] = p->id;
p = p->prev_point;
}
- w[0] = p->id;
+ path[0] = p->id;
}
return path;
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index bf6363aa01..1002f18738 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -169,7 +169,7 @@ public:
void clear();
Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
- Vector<Vector2> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
+ TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
};
VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode);
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 4c89be7f4d..fcf245d2ad 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -30,7 +30,7 @@
#include "aabb.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "core/variant/variant.h"
real_t AABB::get_volume() const {
@@ -76,6 +76,10 @@ bool AABB::is_equal_approx(const AABB &p_aabb) const {
return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
}
+bool AABB::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
AABB AABB::intersection(const AABB &p_aabb) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0 || size.z < 0 || p_aabb.size.x < 0 || p_aabb.size.y < 0 || p_aabb.size.z < 0)) {
@@ -403,6 +407,7 @@ Variant AABB::intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to
}
return Variant();
}
+
Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
Vector3 inters;
if (intersects_ray(p_from, p_dir, &inters)) {
diff --git a/core/math/aabb.h b/core/math/aabb.h
index acf903eeba..9d5837ad37 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -31,7 +31,6 @@
#ifndef AABB_H
#define AABB_H
-#include "core/math/math_defs.h"
#include "core/math/plane.h"
#include "core/math/vector3.h"
@@ -64,6 +63,7 @@ struct _NO_DISCARD_ AABB {
bool operator!=(const AABB &p_rval) const;
bool is_equal_approx(const AABB &p_aabb) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
@@ -101,7 +101,7 @@ struct _NO_DISCARD_ AABB {
_FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */
_FORCE_INLINE_ AABB abs() const {
- return AABB(Vector3(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0), position.z + MIN(size.z, 0)), size.abs());
+ return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs());
}
Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const;
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index 1a80faaa12..d06f9bef1e 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -34,7 +34,7 @@
#include "core/math/vector2.h"
#include "core/typedefs.h"
-static inline float undenormalise(volatile float f) {
+static inline float undenormalize(volatile float f) {
union {
uint32_t i;
float f;
@@ -101,9 +101,9 @@ struct AudioFrame {
r /= p_sample;
}
- _ALWAYS_INLINE_ void undenormalise() {
- l = ::undenormalise(l);
- r = ::undenormalise(r);
+ _ALWAYS_INLINE_ void undenormalize() {
+ l = ::undenormalize(l);
+ r = ::undenormalize(r);
}
_FORCE_INLINE_ AudioFrame lerp(const AudioFrame &p_b, float p_t) const {
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 4b163409ce..41ec6d8ce3 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -31,7 +31,7 @@
#include "basis.h"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#define cofac(row1, col1, row2, col2) \
(rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1])
@@ -142,8 +142,8 @@ bool Basis::is_symmetric() const {
#endif
Basis Basis::diagonalize() {
-//NOTE: only implemented for symmetric matrices
-//with the Jacobi iterative method
+// NOTE: only implemented for symmetric matrices
+// with the Jacobi iterative method
#ifdef MATH_CHECKS
ERR_FAIL_COND_V(!is_symmetric(), Basis());
#endif
@@ -453,7 +453,7 @@ void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) cons
Vector3 Basis::get_euler(EulerOrder p_order) const {
switch (p_order) {
- case EULER_ORDER_XYZ: {
+ case EulerOrder::XYZ: {
// Euler angles in XYZ convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -488,7 +488,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
} break;
- case EULER_ORDER_XZY: {
+ case EulerOrder::XZY: {
// Euler angles in XZY convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -517,7 +517,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
} break;
- case EULER_ORDER_YXZ: {
+ case EulerOrder::YXZ: {
// Euler angles in YXZ convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -555,7 +555,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
return euler;
} break;
- case EULER_ORDER_YZX: {
+ case EulerOrder::YZX: {
// Euler angles in YZX convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -584,7 +584,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
} break;
- case EULER_ORDER_ZXY: {
+ case EulerOrder::ZXY: {
// Euler angles in ZXY convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -612,7 +612,7 @@ Vector3 Basis::get_euler(EulerOrder p_order) const {
}
return euler;
} break;
- case EULER_ORDER_ZYX: {
+ case EulerOrder::ZYX: {
// Euler angles in ZYX convention.
// See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
//
@@ -663,22 +663,22 @@ void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) {
Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1);
switch (p_order) {
- case EULER_ORDER_XYZ: {
+ case EulerOrder::XYZ: {
*this = xmat * (ymat * zmat);
} break;
- case EULER_ORDER_XZY: {
+ case EulerOrder::XZY: {
*this = xmat * zmat * ymat;
} break;
- case EULER_ORDER_YXZ: {
+ case EulerOrder::YXZ: {
*this = ymat * xmat * zmat;
} break;
- case EULER_ORDER_YZX: {
+ case EulerOrder::YZX: {
*this = ymat * zmat * xmat;
} break;
- case EULER_ORDER_ZXY: {
+ case EulerOrder::ZXY: {
*this = zmat * xmat * ymat;
} break;
- case EULER_ORDER_ZYX: {
+ case EulerOrder::ZYX: {
*this = zmat * ymat * xmat;
} break;
default: {
@@ -691,6 +691,10 @@ bool Basis::is_equal_approx(const Basis &p_basis) const {
return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]);
}
+bool Basis::is_finite() const {
+ return rows[0].is_finite() && rows[1].is_finite() && rows[2].is_finite();
+}
+
bool Basis::operator==(const Basis &p_matrix) const {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
@@ -811,7 +815,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
return;
}
// As we have reached here there are no singularities so we can handle normally.
- double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise.
+ double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalize.
if (Math::abs(s) < CMP_EPSILON) {
// Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above.
diff --git a/core/math/basis.h b/core/math/basis.h
index cc2924f5ff..a1d9fccef1 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -56,15 +56,6 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ real_t determinant() const;
- enum EulerOrder {
- EULER_ORDER_XYZ,
- EULER_ORDER_XZY,
- EULER_ORDER_YXZ,
- EULER_ORDER_YZX,
- EULER_ORDER_ZXY,
- EULER_ORDER_ZYX
- };
-
void from_z(const Vector3 &p_z);
void rotate(const Vector3 &p_axis, real_t p_angle);
@@ -73,13 +64,13 @@ struct _NO_DISCARD_ Basis {
void rotate_local(const Vector3 &p_axis, real_t p_angle);
Basis rotated_local(const Vector3 &p_axis, real_t p_angle) const;
- void rotate(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
- Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) const;
+ void rotate(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
+ Basis rotated(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) const;
void rotate(const Quaternion &p_quaternion);
Basis rotated(const Quaternion &p_quaternion) const;
- Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) const;
+ Vector3 get_euler_normalized(EulerOrder p_order = EulerOrder::YXZ) const;
void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const;
void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const;
Quaternion get_rotation_quaternion() const;
@@ -88,9 +79,9 @@ struct _NO_DISCARD_ Basis {
Vector3 rotref_posscale_decomposition(Basis &rotref) const;
- Vector3 get_euler(EulerOrder p_order = EULER_ORDER_YXZ) const;
- void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ);
- static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) {
+ Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
+ void set_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ);
+ static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EulerOrder::YXZ) {
Basis b;
b.set_euler(p_euler, p_order);
return b;
@@ -119,7 +110,7 @@ struct _NO_DISCARD_ Basis {
Vector3 get_scale_local() const;
void set_axis_angle_scale(const Vector3 &p_axis, real_t p_angle, const Vector3 &p_scale);
- void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EULER_ORDER_YXZ);
+ void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale, EulerOrder p_order = EulerOrder::YXZ);
void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale);
// transposed dot products
@@ -134,6 +125,7 @@ struct _NO_DISCARD_ Basis {
}
bool is_equal_approx(const Basis &p_basis) const;
+ bool is_finite() const;
bool operator==(const Basis &p_matrix) const;
bool operator!=(const Basis &p_matrix) const;
diff --git a/core/math/bvh_abb.h b/core/math/bvh_abb.h
index 8a44f1c4da..699f7de604 100644
--- a/core/math/bvh_abb.h
+++ b/core/math/bvh_abb.h
@@ -251,7 +251,9 @@ struct BVH_ABB {
void expand(real_t p_change) {
POINT change;
- change.set_all(p_change);
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
+ change[axis] = p_change;
+ }
grow(change);
}
@@ -262,7 +264,9 @@ struct BVH_ABB {
}
void set_to_max_opposite_extents() {
- neg_max.set_all(FLT_MAX);
+ for (int axis = 0; axis < POINT::AXIS_COUNT; ++axis) {
+ neg_max[axis] = FLT_MAX;
+ }
min = neg_max;
}
diff --git a/core/math/bvh_split.inc b/core/math/bvh_split.inc
index ff07166d4a..180bbfb511 100644
--- a/core/math/bvh_split.inc
+++ b/core/math/bvh_split.inc
@@ -13,7 +13,7 @@ void _split_inform_references(uint32_t p_node_id) {
void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, uint16_t *group_b, const BVHABB_CLASS *temp_bounds, const BVHABB_CLASS full_bound) {
// special case for low leaf sizes .. should static compile out
- if (MAX_ITEMS < 4) {
+ if constexpr (MAX_ITEMS < 4) {
uint32_t ind = group_a[0];
// add to b
@@ -34,7 +34,7 @@ void _split_leaf_sort_groups_simple(int &num_a, int &num_b, uint16_t *group_a, u
order[POINT::AXIS_COUNT - 1] = size.max_axis_index();
static_assert(POINT::AXIS_COUNT <= 3, "BVH POINT::AXIS_COUNT has unexpected size");
- if (POINT::AXIS_COUNT == 3) {
+ if constexpr (POINT::AXIS_COUNT == 3) {
order[1] = 3 - (order[0] + order[2]);
}
diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc
index 58c8f0479a..06f6e5d05d 100644
--- a/core/math/bvh_structs.inc
+++ b/core/math/bvh_structs.inc
@@ -100,7 +100,11 @@ public:
num_items++;
return id;
}
+#ifdef DEV_ENABLED
return -1;
+#else
+ ERR_FAIL_V_MSG(0, "BVH request_item error.");
+#endif
}
};
diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h
index cdb2bb4413..3836e92a83 100644
--- a/core/math/bvh_tree.h
+++ b/core/math/bvh_tree.h
@@ -43,7 +43,6 @@
#include "core/math/bvh_abb.h"
#include "core/math/geometry_3d.h"
#include "core/math/vector3.h"
-#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/pooled_list.h"
#include <limits.h>
@@ -235,7 +234,7 @@ private:
// no need to keep back references for children at the moment
- uint32_t sibling_id; // always a node id, as tnode is never a leaf
+ uint32_t sibling_id = 0; // always a node id, as tnode is never a leaf
bool sibling_present = false;
// if there are more children, or this is the root node, don't try and delete
diff --git a/core/math/color.cpp b/core/math/color.cpp
index 4bdeafd2f2..f223853f6b 100644
--- a/core/math/color.cpp
+++ b/core/math/color.cpp
@@ -32,85 +32,85 @@
#include "color_names.inc"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
#include "core/templates/rb_map.h"
#include "thirdparty/misc/ok_color.h"
uint32_t Color::to_argb32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
+ uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
+ c |= (uint8_t)Math::round(r * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
return c;
}
uint32_t Color::to_abgr32() const {
- uint32_t c = (uint8_t)Math::round(a * 255);
+ uint32_t c = (uint8_t)Math::round(a * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(r * 255);
+ c |= (uint8_t)Math::round(r * 255.0f);
return c;
}
uint32_t Color::to_rgba32() const {
- uint32_t c = (uint8_t)Math::round(r * 255);
+ uint32_t c = (uint8_t)Math::round(r * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(g * 255);
+ c |= (uint8_t)Math::round(g * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(b * 255);
+ c |= (uint8_t)Math::round(b * 255.0f);
c <<= 8;
- c |= (uint8_t)Math::round(a * 255);
+ c |= (uint8_t)Math::round(a * 255.0f);
return c;
}
uint64_t Color::to_abgr64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
+ uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
+ c |= (uint16_t)Math::round(r * 65535.0f);
return c;
}
uint64_t Color::to_argb64() const {
- uint64_t c = (uint16_t)Math::round(a * 65535);
+ uint64_t c = (uint16_t)Math::round(a * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(r * 65535);
+ c |= (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
return c;
}
uint64_t Color::to_rgba64() const {
- uint64_t c = (uint16_t)Math::round(r * 65535);
+ uint64_t c = (uint16_t)Math::round(r * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(g * 65535);
+ c |= (uint16_t)Math::round(g * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(b * 65535);
+ c |= (uint16_t)Math::round(b * 65535.0f);
c <<= 16;
- c |= (uint16_t)Math::round(a * 65535);
+ c |= (uint16_t)Math::round(a * 65535.0f);
return c;
}
String _to_hex(float p_val) {
- int v = Math::round(p_val * 255);
+ int v = Math::round(p_val * 255.0f);
v = CLAMP(v, 0, 255);
String ret;
@@ -150,8 +150,8 @@ float Color::get_h() const {
float delta = max - min;
- if (delta == 0) {
- return 0;
+ if (delta == 0.0f) {
+ return 0.0f;
}
float h;
@@ -164,7 +164,7 @@ float Color::get_h() const {
}
h /= 6.0f;
- if (h < 0) {
+ if (h < 0.0f) {
h += 1.0f;
}
@@ -179,7 +179,7 @@ float Color::get_s() const {
float delta = max - min;
- return (max != 0) ? (delta / max) : 0;
+ return (max != 0.0f) ? (delta / max) : 0.0f;
}
float Color::get_v() const {
@@ -193,7 +193,7 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
float f, p, q, t;
a = p_alpha;
- if (p_s == 0) {
+ if (p_s == 0.0f) {
// Achromatic (grey)
r = g = b = p_v;
return;
@@ -204,9 +204,9 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
i = Math::floor(p_h);
f = p_h - i;
- p = p_v * (1 - p_s);
- q = p_v * (1 - p_s * f);
- t = p_v * (1 - p_s * (1 - f));
+ p = p_v * (1.0f - p_s);
+ q = p_v * (1.0f - p_s * f);
+ t = p_v * (1.0f - p_s * (1.0f - f));
switch (i) {
case 0: // Red is the dominant color
@@ -347,7 +347,7 @@ Color Color::html(const String &p_rgba) {
ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_rgba + ".");
}
- float r, g, b, a = 1.0;
+ float r, g, b, a = 1.0f;
if (is_shorthand) {
r = _parse_col4(color, 0) / 15.0f;
g = _parse_col4(color, 1) / 15.0f;
@@ -363,10 +363,10 @@ Color Color::html(const String &p_rgba) {
a = _parse_col8(color, 6) / 255.0f;
}
}
- ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_rgba + ".");
- ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(r < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(g < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(b < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
+ ERR_FAIL_COND_V_MSG(a < 0.0f, Color(), "Invalid color code: " + p_rgba + ".");
return Color(r, g, b, a);
}
@@ -474,7 +474,7 @@ Color Color::from_rgbe9995(uint32_t p_rgbe) {
float g = (p_rgbe >> 9) & 0x1ff;
float b = (p_rgbe >> 18) & 0x1ff;
float e = (p_rgbe >> 27);
- float m = Math::pow(2, e - 15.0f - 9.0f);
+ float m = Math::pow(2.0f, e - 15.0f - 9.0f);
float rd = r * m;
float gd = g * m;
diff --git a/core/math/color.h b/core/math/color.h
index 65036f74cc..a23a4953ce 100644
--- a/core/math/color.h
+++ b/core/math/color.h
@@ -32,7 +32,8 @@
#define COLOR_H
#include "core/math/math_funcs.h"
-#include "core/string/ustring.h"
+
+class String;
struct _NO_DISCARD_ Color {
union {
@@ -55,11 +56,11 @@ struct _NO_DISCARD_ Color {
float get_h() const;
float get_s() const;
float get_v() const;
- void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
+ void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
float get_ok_hsl_h() const;
float get_ok_hsl_s() const;
float get_ok_hsl_l() const;
- void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0);
+ void set_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f);
_FORCE_INLINE_ float &operator[](int p_idx) {
return components[p_idx];
@@ -175,9 +176,9 @@ struct _NO_DISCARD_ Color {
_FORCE_INLINE_ Color srgb_to_linear() const {
return Color(
- r < 0.04045f ? r * (1.0 / 12.92) : Math::pow((r + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
- g < 0.04045f ? g * (1.0 / 12.92) : Math::pow((g + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
- b < 0.04045f ? b * (1.0 / 12.92) : Math::pow((b + 0.055f) * (float)(1.0 / (1 + 0.055)), 2.4f),
+ r < 0.04045f ? r * (1.0f / 12.92f) : Math::pow((r + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ g < 0.04045f ? g * (1.0f / 12.92f) : Math::pow((g + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
+ b < 0.04045f ? b * (1.0f / 12.92f) : Math::pow((b + 0.055f) * (float)(1.0 / (1.0 + 0.055)), 2.4f),
a);
}
_FORCE_INLINE_ Color linear_to_srgb() const {
@@ -198,11 +199,11 @@ struct _NO_DISCARD_ Color {
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);
- static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0);
- static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0);
+ static Color from_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0f);
+ static Color from_ok_hsl(float p_h, float p_s, float p_l, float p_alpha = 1.0f);
static Color from_rgbe9995(uint32_t p_rgbe);
- _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys
+ _FORCE_INLINE_ bool operator<(const Color &p_color) const; // Used in set keys.
operator String() const;
// For the binder.
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index 996f4f4d67..561970d2ee 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -62,6 +62,7 @@ subject to the following restrictions:
#include "core/math/aabb.h"
#include "core/math/math_defs.h"
#include "core/os/memory.h"
+#include "core/templates/oa_hash_map.h"
#include "core/templates/paged_allocator.h"
#include <string.h>
@@ -2252,19 +2253,62 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
r_mesh.vertices = ch.vertices;
+ // Tag which face each edge belongs to
+ LocalVector<int32_t> edge_faces;
+ edge_faces.resize(ch.edges.size());
+
+ for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ edge_faces[i] = -1;
+ }
+
+ for (uint32_t i = 0; i < ch.faces.size(); i++) {
+ const Edge *e_start = &ch.edges[ch.faces[i]];
+ const Edge *e = e_start;
+ do {
+ int64_t ofs = e - ch.edges.ptr();
+ edge_faces[ofs] = i;
+
+ e = e->get_next_edge_of_face();
+ } while (e != e_start);
+ }
+
// Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them.
r_mesh.edges.resize(ch.edges.size() / 2);
+ OAHashMap<uint64_t, int32_t> edge_map;
+ edge_map.reserve(ch.edges.size() * 4); // The higher the capacity, the faster the insert
+
uint32_t edges_copied = 0;
for (uint32_t i = 0; i < ch.edges.size(); i++) {
+ ERR_CONTINUE(edge_faces[i] == -1); // Sanity check
+
uint32_t a = (&ch.edges[i])->get_source_vertex();
uint32_t b = (&ch.edges[i])->get_target_vertex();
if (a < b) { // Copy only the "canonical" edge. For the reverse edge, this will be false.
ERR_BREAK(edges_copied >= (uint32_t)r_mesh.edges.size());
- r_mesh.edges.write[edges_copied].a = a;
- r_mesh.edges.write[edges_copied].b = b;
+ r_mesh.edges[edges_copied].vertex_a = a;
+ r_mesh.edges[edges_copied].vertex_b = b;
+ r_mesh.edges[edges_copied].face_a = edge_faces[i];
+ r_mesh.edges[edges_copied].face_b = -1;
+
+ uint64_t key = a;
+ key <<= 32;
+ key |= b;
+ edge_map.insert(key, edges_copied);
+
edges_copied++;
+ } else {
+ uint64_t key = b;
+ key <<= 32;
+ key |= a;
+ int32_t index;
+ if (!edge_map.lookup(key, index)) {
+ ERR_PRINT("Invalid edge");
+ } else {
+ r_mesh.edges[index].face_b = edge_faces[i];
+ }
}
}
+
if (edges_copied != (uint32_t)r_mesh.edges.size()) {
ERR_PRINT("Invalid edge count.");
}
@@ -2273,7 +2317,7 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
for (uint32_t i = 0; i < ch.faces.size(); i++) {
const Edge *e_start = &ch.edges[ch.faces[i]];
const Edge *e = e_start;
- Geometry3D::MeshData::Face &face = r_mesh.faces.write[i];
+ Geometry3D::MeshData::Face &face = r_mesh.faces[i];
do {
face.indices.push_back(e->get_target_vertex());
@@ -2284,8 +2328,8 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
// reverse indices: Godot wants clockwise, but this is counter-clockwise
if (face.indices.size() > 2) {
// reverse all but the first index.
- int *indices = face.indices.ptrw();
- for (int c = 0; c < (face.indices.size() - 1) / 2; c++) {
+ int *indices = face.indices.ptr();
+ for (uint32_t c = 0; c < (face.indices.size() - 1) / 2; c++) {
SWAP(indices[c + 1], indices[face.indices.size() - 1 - c]);
}
}
diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h
index bd86fe0eba..ab6671a7d0 100644
--- a/core/math/convex_hull.h
+++ b/core/math/convex_hull.h
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef CONVEX_HULL_H
+#define CONVEX_HULL_H
+
/*
Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net
This software is provided 'as-is', without any express or implied warranty.
@@ -40,9 +43,6 @@ subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
-#ifndef CONVEX_HULL_H
-#define CONVEX_HULL_H
-
#include "core/math/geometry_3d.h"
#include "core/math/vector3.h"
#include "core/templates/local_vector.h"
@@ -62,6 +62,10 @@ public:
friend class ConvexHullComputer;
public:
+ int32_t get_next_relative() const {
+ return next;
+ }
+
int32_t get_source_vertex() const {
return (this + reverse)->target_vertex;
}
@@ -86,7 +90,7 @@ public:
};
// Vertices of the output hull
- Vector<Vector3> vertices;
+ LocalVector<Vector3> vertices;
// Edges of the output hull
LocalVector<Edge> edges;
diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h
index 898c3c2d91..3f8fe09445 100644
--- a/core/math/delaunay_3d.h
+++ b/core/math/delaunay_3d.h
@@ -35,7 +35,6 @@
#include "core/math/aabb.h"
#include "core/math/projection.h"
#include "core/math/vector3.h"
-#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/vector.h"
@@ -186,25 +185,25 @@ class Delaunay3D {
Projection cm;
- cm.matrix[0][0] = p_points[p_simplex.points[0]].x;
- cm.matrix[0][1] = p_points[p_simplex.points[1]].x;
- cm.matrix[0][2] = p_points[p_simplex.points[2]].x;
- cm.matrix[0][3] = p_points[p_simplex.points[3]].x;
-
- cm.matrix[1][0] = p_points[p_simplex.points[0]].y;
- cm.matrix[1][1] = p_points[p_simplex.points[1]].y;
- cm.matrix[1][2] = p_points[p_simplex.points[2]].y;
- cm.matrix[1][3] = p_points[p_simplex.points[3]].y;
-
- cm.matrix[2][0] = p_points[p_simplex.points[0]].z;
- cm.matrix[2][1] = p_points[p_simplex.points[1]].z;
- cm.matrix[2][2] = p_points[p_simplex.points[2]].z;
- cm.matrix[2][3] = p_points[p_simplex.points[3]].z;
-
- cm.matrix[3][0] = 1.0;
- cm.matrix[3][1] = 1.0;
- cm.matrix[3][2] = 1.0;
- cm.matrix[3][3] = 1.0;
+ cm.columns[0][0] = p_points[p_simplex.points[0]].x;
+ cm.columns[0][1] = p_points[p_simplex.points[1]].x;
+ cm.columns[0][2] = p_points[p_simplex.points[2]].x;
+ cm.columns[0][3] = p_points[p_simplex.points[3]].x;
+
+ cm.columns[1][0] = p_points[p_simplex.points[0]].y;
+ cm.columns[1][1] = p_points[p_simplex.points[1]].y;
+ cm.columns[1][2] = p_points[p_simplex.points[2]].y;
+ cm.columns[1][3] = p_points[p_simplex.points[3]].y;
+
+ cm.columns[2][0] = p_points[p_simplex.points[0]].z;
+ cm.columns[2][1] = p_points[p_simplex.points[1]].z;
+ cm.columns[2][2] = p_points[p_simplex.points[2]].z;
+ cm.columns[2][3] = p_points[p_simplex.points[3]].z;
+
+ cm.columns[3][0] = 1.0;
+ cm.columns[3][1] = 1.0;
+ cm.columns[3][2] = 1.0;
+ cm.columns[3][3] = 1.0;
return ABS(cm.determinant()) <= CMP_EPSILON;
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index e230b69dc9..26b809e7f2 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -560,7 +560,7 @@ const char *Expression::token_name[TK_MAX] = {
};
Expression::ENode *Expression::_parse_expression() {
- Vector<ExpressionNode> expression;
+ Vector<ExpressionNode> expression_nodes;
while (true) {
//keep appending stuff to expression
@@ -838,14 +838,14 @@ Expression::ENode *Expression::_parse_expression() {
ExpressionNode e;
e.is_op = true;
e.op = Variant::OP_NEGATE;
- expression.push_back(e);
+ expression_nodes.push_back(e);
continue;
} break;
case TK_OP_NOT: {
ExpressionNode e;
e.is_op = true;
e.op = Variant::OP_NOT;
- expression.push_back(e);
+ expression_nodes.push_back(e);
continue;
} break;
@@ -960,7 +960,7 @@ Expression::ENode *Expression::_parse_expression() {
ExpressionNode e;
e.is_op = false;
e.node = expr;
- expression.push_back(e);
+ expression_nodes.push_back(e);
}
//ok finally look for an operator
@@ -1054,19 +1054,19 @@ Expression::ENode *Expression::_parse_expression() {
ExpressionNode e;
e.is_op = true;
e.op = op;
- expression.push_back(e);
+ expression_nodes.push_back(e);
}
}
/* Reduce the set of expressions and place them in an operator tree, respecting precedence */
- while (expression.size() > 1) {
+ while (expression_nodes.size() > 1) {
int next_op = -1;
int min_priority = 0xFFFFF;
bool is_unary = false;
- for (int i = 0; i < expression.size(); i++) {
- if (!expression[i].is_op) {
+ for (int i = 0; i < expression_nodes.size(); i++) {
+ if (!expression_nodes[i].is_op) {
continue;
}
@@ -1074,7 +1074,7 @@ Expression::ENode *Expression::_parse_expression() {
bool unary = false;
- switch (expression[i].op) {
+ switch (expression_nodes[i].op) {
case Variant::OP_POWER:
priority = 0;
break;
@@ -1130,7 +1130,7 @@ Expression::ENode *Expression::_parse_expression() {
priority = 14;
break;
default: {
- _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
+ _set_error("Parser bug, invalid operator in expression: " + itos(expression_nodes[i].op));
return nullptr;
}
}
@@ -1153,9 +1153,9 @@ Expression::ENode *Expression::_parse_expression() {
// OK! create operator..
if (is_unary) {
int expr_pos = next_op;
- while (expression[expr_pos].is_op) {
+ while (expression_nodes[expr_pos].is_op) {
expr_pos++;
- if (expr_pos == expression.size()) {
+ if (expr_pos == expression_nodes.size()) {
//can happen..
_set_error("Unexpected end of expression...");
return nullptr;
@@ -1165,29 +1165,29 @@ Expression::ENode *Expression::_parse_expression() {
//consecutively do unary operators
for (int i = expr_pos - 1; i >= next_op; i--) {
OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[i].op;
- op->nodes[0] = expression[i + 1].node;
+ op->op = expression_nodes[i].op;
+ op->nodes[0] = expression_nodes[i + 1].node;
op->nodes[1] = nullptr;
- expression.write[i].is_op = false;
- expression.write[i].node = op;
- expression.remove_at(i + 1);
+ expression_nodes.write[i].is_op = false;
+ expression_nodes.write[i].node = op;
+ expression_nodes.remove_at(i + 1);
}
} else {
- if (next_op < 1 || next_op >= (expression.size() - 1)) {
+ if (next_op < 1 || next_op >= (expression_nodes.size() - 1)) {
_set_error("Parser bug...");
ERR_FAIL_V(nullptr);
}
OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[next_op].op;
+ op->op = expression_nodes[next_op].op;
- if (expression[next_op - 1].is_op) {
+ if (expression_nodes[next_op - 1].is_op) {
_set_error("Parser bug...");
ERR_FAIL_V(nullptr);
}
- if (expression[next_op + 1].is_op) {
+ if (expression_nodes[next_op + 1].is_op) {
// this is not invalid and can really appear
// but it becomes invalid anyway because no binary op
// can be followed by a unary op in a valid combination,
@@ -1197,17 +1197,17 @@ Expression::ENode *Expression::_parse_expression() {
return nullptr;
}
- op->nodes[0] = expression[next_op - 1].node; //expression goes as left
- op->nodes[1] = expression[next_op + 1].node; //next expression goes as right
+ op->nodes[0] = expression_nodes[next_op - 1].node; //expression goes as left
+ op->nodes[1] = expression_nodes[next_op + 1].node; //next expression goes as right
//replace all 3 nodes by this operator and make it an expression
- expression.write[next_op - 1].node = op;
- expression.remove_at(next_op);
- expression.remove_at(next_op);
+ expression_nodes.write[next_op - 1].node = op;
+ expression_nodes.remove_at(next_op);
+ expression_nodes.remove_at(next_op);
}
}
- return expression[0].node;
+ return expression_nodes[0].node;
}
bool Expression::_compile_expression() {
@@ -1420,7 +1420,7 @@ bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression:
Callable::CallError ce;
Variant::call_utility_function(bifunc->func, &r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "Builtin Call Failed. " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce);
+ r_error_str = "Builtin call failed: " + Variant::get_call_error_text(bifunc->func, (const Variant **)argp.ptr(), argp.size(), ce);
return true;
}
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 9238293b48..548b9e4620 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -30,8 +30,6 @@
#include "geometry_3d.h"
-#include "core/string/print_string.h"
-
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
@@ -143,21 +141,21 @@ real_t Geometry3D::get_closest_distance_between_segments(const Vector3 &p_p0, co
void Geometry3D::MeshData::optimize_vertices() {
HashMap<int, int> vtx_remap;
- for (int i = 0; i < faces.size(); i++) {
- for (int j = 0; j < faces[i].indices.size(); j++) {
+ for (uint32_t i = 0; i < faces.size(); i++) {
+ for (uint32_t j = 0; j < faces[i].indices.size(); j++) {
int idx = faces[i].indices[j];
if (!vtx_remap.has(idx)) {
int ni = vtx_remap.size();
vtx_remap[idx] = ni;
}
- faces.write[i].indices.write[j] = vtx_remap[idx];
+ faces[i].indices[j] = vtx_remap[idx];
}
}
- for (int i = 0; i < edges.size(); i++) {
- int a = edges[i].a;
- int b = edges[i].b;
+ for (uint32_t i = 0; i < edges.size(); i++) {
+ int a = edges[i].vertex_a;
+ int b = edges[i].vertex_b;
if (!vtx_remap.has(a)) {
int ni = vtx_remap.size();
@@ -168,16 +166,16 @@ void Geometry3D::MeshData::optimize_vertices() {
vtx_remap[b] = ni;
}
- edges.write[i].a = vtx_remap[a];
- edges.write[i].b = vtx_remap[b];
+ edges[i].vertex_a = vtx_remap[a];
+ edges[i].vertex_b = vtx_remap[b];
}
- Vector<Vector3> new_vertices;
+ LocalVector<Vector3> new_vertices;
new_vertices.resize(vtx_remap.size());
- for (int i = 0; i < vertices.size(); i++) {
+ for (uint32_t i = 0; i < vertices.size(); i++) {
if (vtx_remap.has(i)) {
- new_vertices.write[vtx_remap[i]] = vertices[i];
+ new_vertices[vtx_remap[i]] = vertices[i];
}
}
vertices = new_vertices;
@@ -753,7 +751,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
Vector3 center = p.center();
// make a quad clockwise
- Vector<Vector3> vertices = {
+ LocalVector<Vector3> vertices = {
center - up * subplane_size + right * subplane_size,
center - up * subplane_size - right * subplane_size,
center + up * subplane_size - right * subplane_size,
@@ -765,7 +763,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
continue;
}
- Vector<Vector3> new_vertices;
+ LocalVector<Vector3> new_vertices;
Plane clip = p_planes[j];
if (clip.normal.dot(p.normal) > 0.95f) {
@@ -776,7 +774,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
break;
}
- for (int k = 0; k < vertices.size(); k++) {
+ for (uint32_t k = 0; k < vertices.size(); k++) {
int k_n = (k + 1) % vertices.size();
Vector3 edge0_A = vertices[k];
@@ -818,9 +816,9 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
MeshData::Face face;
// Add face indices.
- for (int j = 0; j < vertices.size(); j++) {
+ for (uint32_t j = 0; j < vertices.size(); j++) {
int idx = -1;
- for (int k = 0; k < mesh.vertices.size(); k++) {
+ for (uint32_t k = 0; k < mesh.vertices.size(); k++) {
if (mesh.vertices[k].distance_to(vertices[j]) < 0.001f) {
idx = k;
break;
@@ -839,28 +837,34 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
// Add edge.
- for (int j = 0; j < face.indices.size(); j++) {
+ for (uint32_t j = 0; j < face.indices.size(); j++) {
int a = face.indices[j];
int b = face.indices[(j + 1) % face.indices.size()];
bool found = false;
- for (int k = 0; k < mesh.edges.size(); k++) {
- if (mesh.edges[k].a == a && mesh.edges[k].b == b) {
+ int found_idx = -1;
+ for (uint32_t k = 0; k < mesh.edges.size(); k++) {
+ if (mesh.edges[k].vertex_a == a && mesh.edges[k].vertex_b == b) {
found = true;
+ found_idx = k;
break;
}
- if (mesh.edges[k].b == a && mesh.edges[k].a == b) {
+ if (mesh.edges[k].vertex_b == a && mesh.edges[k].vertex_a == b) {
found = true;
+ found_idx = k;
break;
}
}
if (found) {
+ mesh.edges[found_idx].face_b = j;
continue;
}
MeshData::Edge edge;
- edge.a = a;
- edge.b = b;
+ edge.vertex_a = a;
+ edge.vertex_b = b;
+ edge.face_a = j;
+ edge.face_b = -1;
mesh.edges.push_back(edge);
}
}
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index e5ace9db72..4b4c173a1e 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -33,6 +33,7 @@
#include "core/math/face3.h"
#include "core/object/object.h"
+#include "core/templates/local_vector.h"
#include "core/templates/vector.h"
class Geometry3D {
@@ -539,18 +540,19 @@ public:
struct MeshData {
struct Face {
Plane plane;
- Vector<int> indices;
+ LocalVector<int> indices;
};
- Vector<Face> faces;
+ LocalVector<Face> faces;
struct Edge {
- int a, b;
+ int vertex_a, vertex_b;
+ int face_a, face_b;
};
- Vector<Edge> edges;
+ LocalVector<Edge> edges;
- Vector<Vector3> vertices;
+ LocalVector<Vector3> vertices;
void optimize_vertices();
};
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index b8b82f2ff4..759667e2d5 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -116,6 +116,15 @@ enum Corner {
CORNER_BOTTOM_LEFT
};
+enum class EulerOrder {
+ XYZ,
+ XZY,
+ YXZ,
+ YZX,
+ ZXY,
+ ZYX
+};
+
/**
* The "Real" type is an abstract type used for real numbers, such as 1.5,
* in contrast to integer numbers. Precision can be controlled with the
diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp
index 208f89f449..7b30b9a98c 100644
--- a/core/math/math_fieldwise.cpp
+++ b/core/math/math_fieldwise.cpp
@@ -56,6 +56,15 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+ case Variant::VECTOR2I: {
+ SETUP_TYPE(Vector2i)
+
+ /**/ TRY_TRANSFER_FIELD("x", x)
+ else TRY_TRANSFER_FIELD("y", y)
+
+ return target;
+ }
+
case Variant::RECT2: {
SETUP_TYPE(Rect2)
@@ -67,6 +76,17 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+ case Variant::RECT2I: {
+ SETUP_TYPE(Rect2i)
+
+ /**/ TRY_TRANSFER_FIELD("x", position.x)
+ else TRY_TRANSFER_FIELD("y", position.y)
+ else TRY_TRANSFER_FIELD("w", size.x)
+ else TRY_TRANSFER_FIELD("h", size.y)
+
+ return target;
+ }
+
case Variant::VECTOR3: {
SETUP_TYPE(Vector3)
@@ -76,6 +96,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR3I: {
SETUP_TYPE(Vector3i)
@@ -85,6 +106,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR4: {
SETUP_TYPE(Vector4)
@@ -95,6 +117,7 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+
case Variant::VECTOR4I: {
SETUP_TYPE(Vector4i)
@@ -106,7 +129,6 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
-
case Variant::PLANE: {
SETUP_TYPE(Plane)
@@ -190,6 +212,29 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
return target;
}
+ case Variant::PROJECTION: {
+ SETUP_TYPE(Projection)
+
+ /**/ TRY_TRANSFER_FIELD("xx", columns[0].x)
+ else TRY_TRANSFER_FIELD("xy", columns[0].y)
+ else TRY_TRANSFER_FIELD("xz", columns[0].z)
+ else TRY_TRANSFER_FIELD("xw", columns[0].w)
+ else TRY_TRANSFER_FIELD("yx", columns[1].x)
+ else TRY_TRANSFER_FIELD("yy", columns[1].y)
+ else TRY_TRANSFER_FIELD("yz", columns[1].z)
+ else TRY_TRANSFER_FIELD("yw", columns[1].w)
+ else TRY_TRANSFER_FIELD("zx", columns[2].x)
+ else TRY_TRANSFER_FIELD("zy", columns[2].y)
+ else TRY_TRANSFER_FIELD("zz", columns[2].z)
+ else TRY_TRANSFER_FIELD("zw", columns[2].w)
+ else TRY_TRANSFER_FIELD("xo", columns[3].x)
+ else TRY_TRANSFER_FIELD("yo", columns[3].y)
+ else TRY_TRANSFER_FIELD("zo", columns[3].z)
+ else TRY_TRANSFER_FIELD("wo", columns[3].w)
+
+ return target;
+ }
+
default: {
ERR_FAIL_V(p_target);
}
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 656fc9f798..0af529ad98 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -184,6 +184,9 @@ public:
#endif
}
+ static _ALWAYS_INLINE_ bool is_finite(double p_val) { return isfinite(p_val); }
+ static _ALWAYS_INLINE_ bool is_finite(float p_val) { return isfinite(p_val); }
+
static _ALWAYS_INLINE_ double abs(double g) { return absd(g); }
static _ALWAYS_INLINE_ float abs(float g) { return absf(g); }
static _ALWAYS_INLINE_ int abs(int g) { return g > 0 ? g : -g; }
@@ -267,6 +270,7 @@ public:
return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
float from_rot = fmod(p_from, (float)Math_TAU);
@@ -293,6 +297,7 @@ public:
double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
/* Barry-Goldman method */
@@ -320,6 +325,7 @@ public:
return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
}
+
static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
float p_to_t, float p_pre_t, float p_post_t) {
float from_rot = fmod(p_from, (float)Math_TAU);
@@ -346,6 +352,7 @@ public:
return p_start * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3;
}
+
static _ALWAYS_INLINE_ float bezier_interpolate(float p_start, float p_control_1, float p_control_2, float p_end, float p_t) {
/* Formula from Wikipedia article on Bezier curves. */
float omt = (1.0f - p_t);
@@ -368,11 +375,19 @@ public:
return p_from + distance * p_weight;
}
- static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) { return (p_value - p_from) / (p_to - p_from); }
- static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) { return (p_value - p_from) / (p_to - p_from); }
+ static _ALWAYS_INLINE_ double inverse_lerp(double p_from, double p_to, double p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+ }
+ static _ALWAYS_INLINE_ float inverse_lerp(float p_from, float p_to, float p_value) {
+ return (p_value - p_from) / (p_to - p_from);
+ }
- static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
- static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double remap(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+ }
+ static _ALWAYS_INLINE_ float remap(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) {
+ return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value));
+ }
static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_s) {
if (is_equal_approx(p_from, p_to)) {
@@ -388,14 +403,26 @@ public:
float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f);
return s * s * (3.0f - 2.0f * s);
}
- static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
- static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
+ static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) {
+ return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
+ }
+ static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) {
+ return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta;
+ }
- static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ double linear_to_db(double p_linear) {
+ return Math::log(p_linear) * 8.6858896380650365530225783783321;
+ }
+ static _ALWAYS_INLINE_ float linear_to_db(float p_linear) {
+ return Math::log(p_linear) * (float)8.6858896380650365530225783783321;
+ }
- static _ALWAYS_INLINE_ double db_to_linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db_to_linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ double db_to_linear(double p_db) {
+ return Math::exp(p_db * 0.11512925464970228420089957273422);
+ }
+ static _ALWAYS_INLINE_ float db_to_linear(float p_db) {
+ return Math::exp(p_db * (float)0.11512925464970228420089957273422);
+ }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index 6881ad4014..a5d2fe5628 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -147,6 +147,7 @@ Variant Plane::intersect_3_bind(const Plane &p_plane1, const Plane &p_plane2) co
return Variant();
}
}
+
Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) const {
Vector3 inters;
if (intersects_ray(p_from, p_dir, &inters)) {
@@ -155,6 +156,7 @@ Variant Plane::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir)
return Variant();
}
}
+
Variant Plane::intersects_segment_bind(const Vector3 &p_begin, const Vector3 &p_end) const {
Vector3 inters;
if (intersects_segment(p_begin, p_end, &inters)) {
@@ -174,6 +176,10 @@ bool Plane::is_equal_approx(const Plane &p_plane) const {
return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
}
+bool Plane::is_finite() const {
+ return normal.is_finite() && Math::is_finite(d);
+}
+
Plane::operator String() const {
return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]";
}
diff --git a/core/math/plane.h b/core/math/plane.h
index 73babfa496..77da59fb27 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -74,6 +74,7 @@ struct _NO_DISCARD_ Plane {
Plane operator-() const { return Plane(-normal, -d); }
bool is_equal_approx(const Plane &p_plane) const;
bool is_equal_approx_any_side(const Plane &p_plane) const;
+ bool is_finite() const;
_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index 863fe6ee79..70cc9b5f7c 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -35,27 +35,27 @@
#include "core/math/plane.h"
#include "core/math/rect2.h"
#include "core/math/transform_3d.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
float Projection::determinant() const {
- return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] -
- matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] +
- matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] -
- matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] +
- matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] -
- matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] +
- matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] -
- matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] +
- matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] -
- matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] +
- matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] -
- matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3];
+ return columns[0][3] * columns[1][2] * columns[2][1] * columns[3][0] - columns[0][2] * columns[1][3] * columns[2][1] * columns[3][0] -
+ columns[0][3] * columns[1][1] * columns[2][2] * columns[3][0] + columns[0][1] * columns[1][3] * columns[2][2] * columns[3][0] +
+ columns[0][2] * columns[1][1] * columns[2][3] * columns[3][0] - columns[0][1] * columns[1][2] * columns[2][3] * columns[3][0] -
+ columns[0][3] * columns[1][2] * columns[2][0] * columns[3][1] + columns[0][2] * columns[1][3] * columns[2][0] * columns[3][1] +
+ columns[0][3] * columns[1][0] * columns[2][2] * columns[3][1] - columns[0][0] * columns[1][3] * columns[2][2] * columns[3][1] -
+ columns[0][2] * columns[1][0] * columns[2][3] * columns[3][1] + columns[0][0] * columns[1][2] * columns[2][3] * columns[3][1] +
+ columns[0][3] * columns[1][1] * columns[2][0] * columns[3][2] - columns[0][1] * columns[1][3] * columns[2][0] * columns[3][2] -
+ columns[0][3] * columns[1][0] * columns[2][1] * columns[3][2] + columns[0][0] * columns[1][3] * columns[2][1] * columns[3][2] +
+ columns[0][1] * columns[1][0] * columns[2][3] * columns[3][2] - columns[0][0] * columns[1][1] * columns[2][3] * columns[3][2] -
+ columns[0][2] * columns[1][1] * columns[2][0] * columns[3][3] + columns[0][1] * columns[1][2] * columns[2][0] * columns[3][3] +
+ columns[0][2] * columns[1][0] * columns[2][1] * columns[3][3] - columns[0][0] * columns[1][2] * columns[2][1] * columns[3][3] -
+ columns[0][1] * columns[1][0] * columns[2][2] * columns[3][3] + columns[0][0] * columns[1][1] * columns[2][2] * columns[3][3];
}
void Projection::set_identity() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- matrix[i][j] = (i == j) ? 1 : 0;
+ columns[i][j] = (i == j) ? 1 : 0;
}
}
}
@@ -63,7 +63,7 @@ void Projection::set_identity() {
void Projection::set_zero() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- matrix[i][j] = 0;
+ columns[i][j] = 0;
}
}
}
@@ -71,26 +71,26 @@ void Projection::set_zero() {
Plane Projection::xform4(const Plane &p_vec4) const {
Plane ret;
- ret.normal.x = matrix[0][0] * p_vec4.normal.x + matrix[1][0] * p_vec4.normal.y + matrix[2][0] * p_vec4.normal.z + matrix[3][0] * p_vec4.d;
- ret.normal.y = matrix[0][1] * p_vec4.normal.x + matrix[1][1] * p_vec4.normal.y + matrix[2][1] * p_vec4.normal.z + matrix[3][1] * p_vec4.d;
- ret.normal.z = matrix[0][2] * p_vec4.normal.x + matrix[1][2] * p_vec4.normal.y + matrix[2][2] * p_vec4.normal.z + matrix[3][2] * p_vec4.d;
- ret.d = matrix[0][3] * p_vec4.normal.x + matrix[1][3] * p_vec4.normal.y + matrix[2][3] * p_vec4.normal.z + matrix[3][3] * p_vec4.d;
+ ret.normal.x = columns[0][0] * p_vec4.normal.x + columns[1][0] * p_vec4.normal.y + columns[2][0] * p_vec4.normal.z + columns[3][0] * p_vec4.d;
+ ret.normal.y = columns[0][1] * p_vec4.normal.x + columns[1][1] * p_vec4.normal.y + columns[2][1] * p_vec4.normal.z + columns[3][1] * p_vec4.d;
+ ret.normal.z = columns[0][2] * p_vec4.normal.x + columns[1][2] * p_vec4.normal.y + columns[2][2] * p_vec4.normal.z + columns[3][2] * p_vec4.d;
+ ret.d = columns[0][3] * p_vec4.normal.x + columns[1][3] * p_vec4.normal.y + columns[2][3] * p_vec4.normal.z + columns[3][3] * p_vec4.d;
return ret;
}
Vector4 Projection::xform(const Vector4 &p_vec4) const {
return Vector4(
- matrix[0][0] * p_vec4.x + matrix[1][0] * p_vec4.y + matrix[2][0] * p_vec4.z + matrix[3][0] * p_vec4.w,
- matrix[0][1] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[2][1] * p_vec4.z + matrix[3][1] * p_vec4.w,
- matrix[0][2] * p_vec4.x + matrix[1][2] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[3][2] * p_vec4.w,
- matrix[0][3] * p_vec4.x + matrix[1][3] * p_vec4.y + matrix[2][3] * p_vec4.z + matrix[3][3] * p_vec4.w);
+ columns[0][0] * p_vec4.x + columns[1][0] * p_vec4.y + columns[2][0] * p_vec4.z + columns[3][0] * p_vec4.w,
+ columns[0][1] * p_vec4.x + columns[1][1] * p_vec4.y + columns[2][1] * p_vec4.z + columns[3][1] * p_vec4.w,
+ columns[0][2] * p_vec4.x + columns[1][2] * p_vec4.y + columns[2][2] * p_vec4.z + columns[3][2] * p_vec4.w,
+ columns[0][3] * p_vec4.x + columns[1][3] * p_vec4.y + columns[2][3] * p_vec4.z + columns[3][3] * p_vec4.w);
}
Vector4 Projection::xform_inv(const Vector4 &p_vec4) const {
return Vector4(
- matrix[0][0] * p_vec4.x + matrix[0][1] * p_vec4.y + matrix[0][2] * p_vec4.z + matrix[0][3] * p_vec4.w,
- matrix[1][0] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[1][2] * p_vec4.z + matrix[1][3] * p_vec4.w,
- matrix[2][0] * p_vec4.x + matrix[2][1] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[2][3] * p_vec4.w,
- matrix[3][0] * p_vec4.x + matrix[3][1] * p_vec4.y + matrix[3][2] * p_vec4.z + matrix[3][3] * p_vec4.w);
+ columns[0][0] * p_vec4.x + columns[0][1] * p_vec4.y + columns[0][2] * p_vec4.z + columns[0][3] * p_vec4.w,
+ columns[1][0] * p_vec4.x + columns[1][1] * p_vec4.y + columns[1][2] * p_vec4.z + columns[1][3] * p_vec4.w,
+ columns[2][0] * p_vec4.x + columns[2][1] * p_vec4.y + columns[2][2] * p_vec4.z + columns[2][3] * p_vec4.w,
+ columns[3][0] * p_vec4.x + columns[3][1] * p_vec4.y + columns[3][2] * p_vec4.z + columns[3][3] * p_vec4.w);
}
void Projection::adjust_perspective_znear(real_t p_new_znear) {
@@ -98,8 +98,8 @@ void Projection::adjust_perspective_znear(real_t p_new_znear) {
real_t znear = p_new_znear;
real_t deltaZ = zfar - znear;
- matrix[2][2] = -(zfar + znear) / deltaZ;
- matrix[3][2] = -2 * znear * zfar / deltaZ;
+ columns[2][2] = -(zfar + znear) / deltaZ;
+ columns[3][2] = -2 * znear * zfar / deltaZ;
}
Projection Projection::create_depth_correction(bool p_flip_y) {
@@ -169,7 +169,7 @@ Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const {
}
Plane Projection::get_projection_plane(Planes p_plane) const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
switch (p_plane) {
case PLANE_NEAR: {
@@ -267,12 +267,12 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
set_identity();
- matrix[0][0] = cotangent / p_aspect;
- matrix[1][1] = cotangent;
- matrix[2][2] = -(p_z_far + p_z_near) / deltaZ;
- matrix[2][3] = -1;
- matrix[3][2] = -2 * p_z_near * p_z_far / deltaZ;
- matrix[3][3] = 0;
+ columns[0][0] = cotangent / p_aspect;
+ columns[1][1] = cotangent;
+ columns[2][2] = -(p_z_far + p_z_near) / deltaZ;
+ columns[2][3] = -1;
+ columns[3][2] = -2 * p_z_near * p_z_far / deltaZ;
+ columns[3][3] = 0;
}
void Projection::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, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) {
@@ -309,7 +309,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
// translate matrix by (modeltranslation, 0.0, 0.0)
Projection cm;
cm.set_identity();
- cm.matrix[3][0] = modeltranslation;
+ cm.columns[3][0] = modeltranslation;
*this = *this * cm;
}
@@ -344,13 +344,13 @@ void Projection::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_di
void Projection::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) {
set_identity();
- matrix[0][0] = 2.0 / (p_right - p_left);
- matrix[3][0] = -((p_right + p_left) / (p_right - p_left));
- matrix[1][1] = 2.0 / (p_top - p_bottom);
- matrix[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
- matrix[2][2] = -2.0 / (p_zfar - p_znear);
- matrix[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
- matrix[3][3] = 1.0;
+ columns[0][0] = 2.0 / (p_right - p_left);
+ columns[3][0] = -((p_right + p_left) / (p_right - p_left));
+ columns[1][1] = 2.0 / (p_top - p_bottom);
+ columns[3][1] = -((p_top + p_bottom) / (p_top - p_bottom));
+ columns[2][2] = -2.0 / (p_zfar - p_znear);
+ columns[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear));
+ columns[3][3] = 1.0;
}
void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) {
@@ -366,7 +366,7 @@ void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, rea
ERR_FAIL_COND(p_top <= p_bottom);
ERR_FAIL_COND(p_far <= p_near);
- real_t *te = &matrix[0][0];
+ real_t *te = &columns[0][0];
real_t x = 2 * p_near / (p_right - p_left);
real_t y = 2 * p_near / (p_top - p_bottom);
@@ -402,7 +402,7 @@ void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, r
}
real_t Projection::get_z_far() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane new_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
matrix[11] - matrix[10],
@@ -415,7 +415,7 @@ real_t Projection::get_z_far() const {
}
real_t Projection::get_z_near() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane new_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
matrix[11] + matrix[10],
@@ -426,7 +426,7 @@ real_t Projection::get_z_near() const {
}
Vector2 Projection::get_viewport_half_extents() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
///////--- Near Plane ---///////
Plane near_plane = Plane(matrix[3] + matrix[2],
matrix[7] + matrix[6],
@@ -454,7 +454,7 @@ Vector2 Projection::get_viewport_half_extents() const {
}
Vector2 Projection::get_far_plane_half_extents() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
///////--- Far Plane ---///////
Plane far_plane = Plane(matrix[3] - matrix[2],
matrix[7] - matrix[6],
@@ -496,7 +496,10 @@ bool Projection::get_endpoints(const Transform3D &p_transform, Vector3 *p_8point
for (int i = 0; i < 8; i++) {
Vector3 point;
- bool res = planes[intersections[i][0]].intersect_3(planes[intersections[i][1]], planes[intersections[i][2]], &point);
+ Plane a = planes[intersections[i][0]];
+ Plane b = planes[intersections[i][1]];
+ Plane c = planes[intersections[i][2]];
+ bool res = a.intersect_3(b, c, &point);
ERR_FAIL_COND_V(!res, false);
p_8points[i] = p_transform.xform(point);
}
@@ -514,7 +517,7 @@ Vector<Plane> Projection::get_projection_planes(const Transform3D &p_transform)
Vector<Plane> planes;
planes.resize(6);
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane new_plane;
@@ -601,15 +604,15 @@ void Projection::invert() {
real_t determinant = 1.0f;
for (k = 0; k < 4; k++) {
/** Locate k'th pivot element **/
- pvt_val = matrix[k][k]; /** Initialize for search **/
+ pvt_val = columns[k][k]; /** Initialize for search **/
pvt_i[k] = k;
pvt_j[k] = k;
for (i = k; i < 4; i++) {
for (j = k; j < 4; j++) {
- if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) {
+ if (Math::abs(columns[i][j]) > Math::abs(pvt_val)) {
pvt_i[k] = i;
pvt_j[k] = j;
- pvt_val = matrix[i][j];
+ pvt_val = columns[i][j];
}
}
}
@@ -624,9 +627,9 @@ void Projection::invert() {
i = pvt_i[k];
if (i != k) { /** If rows are different **/
for (j = 0; j < 4; j++) {
- hold = -matrix[k][j];
- matrix[k][j] = matrix[i][j];
- matrix[i][j] = hold;
+ hold = -columns[k][j];
+ columns[k][j] = columns[i][j];
+ columns[i][j] = hold;
}
}
@@ -634,25 +637,25 @@ void Projection::invert() {
j = pvt_j[k];
if (j != k) { /** If columns are different **/
for (i = 0; i < 4; i++) {
- hold = -matrix[i][k];
- matrix[i][k] = matrix[i][j];
- matrix[i][j] = hold;
+ hold = -columns[i][k];
+ columns[i][k] = columns[i][j];
+ columns[i][j] = hold;
}
}
/** Divide column by minus pivot value **/
for (i = 0; i < 4; i++) {
if (i != k) {
- matrix[i][k] /= (-pvt_val);
+ columns[i][k] /= (-pvt_val);
}
}
/** Reduce the matrix **/
for (i = 0; i < 4; i++) {
- hold = matrix[i][k];
+ hold = columns[i][k];
for (j = 0; j < 4; j++) {
if (i != k && j != k) {
- matrix[i][j] += hold * matrix[k][j];
+ columns[i][j] += hold * columns[k][j];
}
}
}
@@ -660,12 +663,12 @@ void Projection::invert() {
/** Divide row by pivot **/
for (j = 0; j < 4; j++) {
if (j != k) {
- matrix[k][j] /= pvt_val;
+ columns[k][j] /= pvt_val;
}
}
/** Replace pivot by reciprocal (at last we can touch it). **/
- matrix[k][k] = 1.0 / pvt_val;
+ columns[k][k] = 1.0 / pvt_val;
}
/* That was most of the work, one final pass of row/column interchange */
@@ -674,18 +677,18 @@ void Projection::invert() {
i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */
if (i != k) { /* If rows are different */
for (j = 0; j < 4; j++) {
- hold = matrix[k][j];
- matrix[k][j] = -matrix[i][j];
- matrix[i][j] = hold;
+ hold = columns[k][j];
+ columns[k][j] = -columns[i][j];
+ columns[i][j] = hold;
}
}
j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */
if (j != k) { /* If columns are different */
for (i = 0; i < 4; i++) {
- hold = matrix[i][k];
- matrix[i][k] = -matrix[i][j];
- matrix[i][j] = hold;
+ hold = columns[i][k];
+ columns[i][k] = -columns[i][j];
+ columns[i][j] = hold;
}
}
}
@@ -693,7 +696,7 @@ void Projection::invert() {
void Projection::flip_y() {
for (int i = 0; i < 4; i++) {
- matrix[1][i] = -matrix[1][i];
+ columns[1][i] = -columns[1][i];
}
}
@@ -708,9 +711,9 @@ Projection Projection::operator*(const Projection &p_matrix) const {
for (int i = 0; i < 4; i++) {
real_t ab = 0;
for (int k = 0; k < 4; k++) {
- ab += matrix[k][i] * p_matrix.matrix[j][k];
+ ab += columns[k][i] * p_matrix.columns[j][k];
}
- new_matrix.matrix[j][i] = ab;
+ new_matrix.columns[j][i] = ab;
}
}
@@ -718,7 +721,7 @@ Projection Projection::operator*(const Projection &p_matrix) const {
}
void Projection::set_depth_correction(bool p_flip_y) {
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = 1;
m[1] = 0.0;
@@ -739,7 +742,7 @@ void Projection::set_depth_correction(bool p_flip_y) {
}
void Projection::set_light_bias() {
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = 0.5;
m[1] = 0.0;
@@ -760,7 +763,7 @@ void Projection::set_light_bias() {
}
void Projection::set_light_atlas_rect(const Rect2 &p_rect) {
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = p_rect.size.width;
m[1] = 0.0;
@@ -784,7 +787,7 @@ Projection::operator String() const {
String str;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
- str += String((j > 0) ? ", " : "\n") + rtos(matrix[i][j]);
+ str += String((j > 0) ? ", " : "\n") + rtos(columns[i][j]);
}
}
@@ -803,11 +806,11 @@ int Projection::get_pixels_per_meter(int p_for_pixel_width) const {
}
bool Projection::is_orthogonal() const {
- return matrix[3][3] == 1.0;
+ return columns[3][3] == 1.0;
}
real_t Projection::get_fov() const {
- const real_t *matrix = (const real_t *)this->matrix;
+ const real_t *matrix = (const real_t *)columns;
Plane right_plane = Plane(matrix[3] - matrix[0],
matrix[7] - matrix[4],
@@ -838,48 +841,49 @@ float Projection::get_lod_multiplier() const {
return 1.0 / (zn / width);
}
- //usage is lod_size / (lod_distance * multiplier) < threshold
+ // Usage is lod_size / (lod_distance * multiplier) < threshold
}
+
void Projection::make_scale(const Vector3 &p_scale) {
set_identity();
- matrix[0][0] = p_scale.x;
- matrix[1][1] = p_scale.y;
- matrix[2][2] = p_scale.z;
+ columns[0][0] = p_scale.x;
+ columns[1][1] = p_scale.y;
+ columns[2][2] = p_scale.z;
}
void Projection::scale_translate_to_fit(const AABB &p_aabb) {
Vector3 min = p_aabb.position;
Vector3 max = p_aabb.position + p_aabb.size;
- matrix[0][0] = 2 / (max.x - min.x);
- matrix[1][0] = 0;
- matrix[2][0] = 0;
- matrix[3][0] = -(max.x + min.x) / (max.x - min.x);
+ columns[0][0] = 2 / (max.x - min.x);
+ columns[1][0] = 0;
+ columns[2][0] = 0;
+ columns[3][0] = -(max.x + min.x) / (max.x - min.x);
- matrix[0][1] = 0;
- matrix[1][1] = 2 / (max.y - min.y);
- matrix[2][1] = 0;
- matrix[3][1] = -(max.y + min.y) / (max.y - min.y);
+ columns[0][1] = 0;
+ columns[1][1] = 2 / (max.y - min.y);
+ columns[2][1] = 0;
+ columns[3][1] = -(max.y + min.y) / (max.y - min.y);
- matrix[0][2] = 0;
- matrix[1][2] = 0;
- matrix[2][2] = 2 / (max.z - min.z);
- matrix[3][2] = -(max.z + min.z) / (max.z - min.z);
+ columns[0][2] = 0;
+ columns[1][2] = 0;
+ columns[2][2] = 2 / (max.z - min.z);
+ columns[3][2] = -(max.z + min.z) / (max.z - min.z);
- matrix[0][3] = 0;
- matrix[1][3] = 0;
- matrix[2][3] = 0;
- matrix[3][3] = 1;
+ columns[0][3] = 0;
+ columns[1][3] = 0;
+ columns[2][3] = 0;
+ columns[3][3] = 1;
}
void Projection::add_jitter_offset(const Vector2 &p_offset) {
- matrix[3][0] += p_offset.x;
- matrix[3][1] += p_offset.y;
+ columns[3][0] += p_offset.x;
+ columns[3][1] += p_offset.y;
}
Projection::operator Transform3D() const {
Transform3D tr;
- const real_t *m = &matrix[0][0];
+ const real_t *m = &columns[0][0];
tr.basis.rows[0][0] = m[0];
tr.basis.rows[1][0] = m[1];
@@ -899,15 +903,17 @@ Projection::operator Transform3D() const {
return tr;
}
+
Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) {
- matrix[0] = p_x;
- matrix[1] = p_y;
- matrix[2] = p_z;
- matrix[3] = p_w;
+ columns[0] = p_x;
+ columns[1] = p_y;
+ columns[2] = p_z;
+ columns[3] = p_w;
}
+
Projection::Projection(const Transform3D &p_transform) {
const Transform3D &tr = p_transform;
- real_t *m = &matrix[0][0];
+ real_t *m = &columns[0][0];
m[0] = tr.basis.rows[0][0];
m[1] = tr.basis.rows[1][0];
diff --git a/core/math/projection.h b/core/math/projection.h
index f149d307b3..38fb9781ae 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -31,10 +31,11 @@
#ifndef PROJECTION_H
#define PROJECTION_H
-#include "core/math/math_defs.h"
#include "core/math/vector3.h"
#include "core/math/vector4.h"
-#include "core/templates/vector.h"
+
+template <class T>
+class Vector;
struct AABB;
struct Plane;
@@ -42,7 +43,7 @@ struct Rect2;
struct Transform3D;
struct Vector2;
-struct Projection {
+struct _NO_DISCARD_ Projection {
enum Planes {
PLANE_NEAR,
PLANE_FAR,
@@ -52,16 +53,16 @@ struct Projection {
PLANE_BOTTOM
};
- Vector4 matrix[4];
+ Vector4 columns[4];
_FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const {
DEV_ASSERT((unsigned int)p_axis < 4);
- return matrix[p_axis];
+ return columns[p_axis];
}
_FORCE_INLINE_ Vector4 &operator[](const int p_axis) {
DEV_ASSERT((unsigned int)p_axis < 4);
- return matrix[p_axis];
+ return columns[p_axis];
}
float determinant() const;
@@ -135,7 +136,7 @@ struct Projection {
bool operator==(const Projection &p_cam) const {
for (uint32_t i = 0; i < 4; i++) {
for (uint32_t j = 0; j < 4; j++) {
- if (matrix[i][j] != p_cam.matrix[i][j]) {
+ if (columns[i][j] != p_cam.columns[i][j]) {
return false;
}
}
@@ -157,10 +158,10 @@ struct Projection {
Vector3 Projection::xform(const Vector3 &p_vec3) const {
Vector3 ret;
- ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0];
- ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1];
- ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2];
- real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3];
+ ret.x = columns[0][0] * p_vec3.x + columns[1][0] * p_vec3.y + columns[2][0] * p_vec3.z + columns[3][0];
+ ret.y = columns[0][1] * p_vec3.x + columns[1][1] * p_vec3.y + columns[2][1] * p_vec3.z + columns[3][1];
+ ret.z = columns[0][2] * p_vec3.x + columns[1][2] * p_vec3.y + columns[2][2] * p_vec3.z + columns[3][2];
+ real_t w = columns[0][3] * p_vec3.x + columns[1][3] * p_vec3.y + columns[2][3] * p_vec3.z + columns[3][3];
return ret / w;
}
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index c836a82e37..942a0b766e 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -31,32 +31,18 @@
#include "quaternion.h"
#include "core/math/basis.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
real_t Quaternion::angle_to(const Quaternion &p_to) const {
real_t d = dot(p_to);
return Math::acos(CLAMP(d * d * 2 - 1, -1, 1));
}
-// 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.
-// This implementation uses XYZ convention (Z is the first rotation).
-Vector3 Quaternion::get_euler_xyz() const {
- Basis m(*this);
- return m.get_euler(Basis::EULER_ORDER_XYZ);
-}
-
-// 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.
-// This implementation uses YXZ convention (Z is the first rotation).
-Vector3 Quaternion::get_euler_yxz() const {
+Vector3 Quaternion::get_euler(EulerOrder p_order) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized.");
#endif
- Basis m(*this);
- return m.get_euler(Basis::EULER_ORDER_YXZ);
+ return Basis(*this).get_euler(p_order);
}
void Quaternion::operator*=(const Quaternion &p_q) {
@@ -79,6 +65,10 @@ bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const {
return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w);
}
+bool Quaternion::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Quaternion::length() const {
return Math::sqrt(length_squared());
}
@@ -326,7 +316,7 @@ Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) {
// (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).
-Quaternion::Quaternion(const Vector3 &p_euler) {
+Quaternion Quaternion::from_euler(const Vector3 &p_euler) {
real_t half_a1 = p_euler.y * 0.5f;
real_t half_a2 = p_euler.x * 0.5f;
real_t half_a3 = p_euler.z * 0.5f;
@@ -342,8 +332,9 @@ Quaternion::Quaternion(const Vector3 &p_euler) {
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;
+ return Quaternion(
+ 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);
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index 43d7bffcfc..c5af2121d9 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -31,10 +31,10 @@
#ifndef QUATERNION_H
#define QUATERNION_H
-#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
#include "core/math/vector3.h"
-#include "core/string/ustring.h"
+
+class String;
struct _NO_DISCARD_ Quaternion {
union {
@@ -55,6 +55,7 @@ struct _NO_DISCARD_ Quaternion {
}
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Quaternion &p_quaternion) const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Quaternion normalized() const;
@@ -65,9 +66,8 @@ struct _NO_DISCARD_ Quaternion {
_FORCE_INLINE_ real_t dot(const Quaternion &p_q) const;
real_t angle_to(const Quaternion &p_to) const;
- Vector3 get_euler_xyz() const;
- Vector3 get_euler_yxz() const;
- Vector3 get_euler() const { return get_euler_yxz(); };
+ Vector3 get_euler(EulerOrder p_order = EulerOrder::YXZ) const;
+ static Quaternion from_euler(const Vector3 &p_euler);
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
@@ -127,8 +127,6 @@ struct _NO_DISCARD_ Quaternion {
Quaternion(const Vector3 &p_axis, real_t p_angle);
- Quaternion(const Vector3 &p_euler);
-
Quaternion(const Quaternion &p_q) :
x(p_q.x),
y(p_q.y),
@@ -143,8 +141,7 @@ struct _NO_DISCARD_ Quaternion {
w = p_q.w;
}
- Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc
- {
+ Quaternion(const Vector3 &v0, const Vector3 &v1) { // Shortest arc.
Vector3 c = v0.cross(v1);
real_t d = v0.dot(v1);
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index c7727a44a1..c194e1cc21 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -369,7 +369,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) {
Geometry3D::MeshData::Face &f = E->get();
- for (int i = 0; i < f.indices.size(); i++) {
+ for (uint32_t i = 0; i < f.indices.size(); i++) {
int a = E->get().indices[i];
int b = E->get().indices[(i + 1) % f.indices.size()];
Edge e(a, b);
@@ -436,17 +436,24 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_
r_mesh.faces.clear();
r_mesh.faces.resize(ret_faces.size());
+ HashMap<List<Geometry3D::MeshData::Face>::Element *, int> face_indices;
+
int idx = 0;
- for (const Geometry3D::MeshData::Face &E : ret_faces) {
- r_mesh.faces.write[idx++] = E;
+ for (List<Geometry3D::MeshData::Face>::Element *E = ret_faces.front(); E; E = E->next()) {
+ face_indices[E] = idx;
+ r_mesh.faces[idx++] = E->get();
}
r_mesh.edges.resize(ret_edges.size());
idx = 0;
for (const KeyValue<Edge, RetFaceConnect> &E : ret_edges) {
Geometry3D::MeshData::Edge e;
- e.a = E.key.vertices[0];
- e.b = E.key.vertices[1];
- r_mesh.edges.write[idx++] = e;
+ e.vertex_a = E.key.vertices[0];
+ e.vertex_b = E.key.vertices[1];
+ ERR_CONTINUE(!face_indices.has(E.value.left));
+ ERR_CONTINUE(!face_indices.has(E.value.right));
+ e.face_a = face_indices[E.value.left];
+ e.face_b = face_indices[E.value.right];
+ r_mesh.edges[idx++] = e;
}
r_mesh.vertices = p_points;
diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h
index 9352bae0a6..bf67154cd6 100644
--- a/core/math/random_number_generator.h
+++ b/core/math/random_number_generator.h
@@ -57,7 +57,7 @@ public:
_FORCE_INLINE_ real_t randfn(real_t p_mean = 0.0, real_t p_deviation = 1.0) { return randbase.randfn(p_mean, p_deviation); }
_FORCE_INLINE_ int randi_range(int p_from, int p_to) { return randbase.random(p_from, p_to); }
- RandomNumberGenerator() {}
+ RandomNumberGenerator() { randbase.randomize(); }
};
#endif // RANDOM_NUMBER_GENERATOR_H
diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp
index 9e78ead816..facf4eb3c4 100644
--- a/core/math/rect2.cpp
+++ b/core/math/rect2.cpp
@@ -38,6 +38,10 @@ bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
}
+bool Rect2::is_finite() const {
+ return position.is_finite() && size.is_finite();
+}
+
bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
diff --git a/core/math/rect2.h b/core/math/rect2.h
index 2d1be3d4f3..9863405d8e 100644
--- a/core/math/rect2.h
+++ b/core/math/rect2.h
@@ -178,7 +178,7 @@ struct _NO_DISCARD_ Rect2 {
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
- new_rect.size = new_rect.size - new_rect.position; //make relative again
+ new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
@@ -207,6 +207,7 @@ struct _NO_DISCARD_ Rect2 {
}
bool is_equal_approx(const Rect2 &p_rect) const;
+ bool is_finite() const;
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; }
@@ -253,7 +254,7 @@ struct _NO_DISCARD_ Rect2 {
return r;
}
- inline void expand_to(const Vector2 &p_vector) { //in place function for speed
+ inline void expand_to(const Vector2 &p_vector) { // In place function for speed.
#ifdef MATH_CHECKS
if (unlikely(size.x < 0 || size.y < 0)) {
ERR_PRINT("Rect2 size is negative, this is not supported. Use Rect2.abs() to get a Rect2 with a positive size.");
@@ -281,7 +282,7 @@ struct _NO_DISCARD_ Rect2 {
}
_FORCE_INLINE_ Rect2 abs() const {
- return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs());
+ return Rect2(Point2(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0)), size.abs());
}
Vector2 get_support(const Vector2 &p_normal) const {
@@ -311,7 +312,7 @@ struct _NO_DISCARD_ Rect2 {
continue;
}
- //check inside
+ // Check inside.
Vector2 tg = r.orthogonal();
float s = tg.dot(center) - tg.dot(a);
if (s < 0.0f) {
@@ -320,7 +321,7 @@ struct _NO_DISCARD_ Rect2 {
side_minus++;
}
- //check ray box
+ // Check ray box.
r /= l;
Vector2 ir(1.0f / r.x, 1.0f / r.y);
@@ -341,7 +342,7 @@ struct _NO_DISCARD_ Rect2 {
}
if (side_plus * side_minus == 0) {
- return true; //all inside
+ return true; // All inside.
} else {
return false;
}
diff --git a/core/math/rect2i.h b/core/math/rect2i.h
index 2b58dcdd98..c92f2cae02 100644
--- a/core/math/rect2i.h
+++ b/core/math/rect2i.h
@@ -121,7 +121,7 @@ struct _NO_DISCARD_ Rect2i {
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y);
- new_rect.size = new_rect.size - new_rect.position; //make relative again
+ new_rect.size = new_rect.size - new_rect.position; // Make relative again.
return new_rect;
}
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 226076029b..548a82d254 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -168,6 +168,10 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]);
}
+bool Transform2D::is_finite() const {
+ return columns[0].is_finite() && columns[1].is_finite() && columns[2].is_finite();
+}
+
Transform2D Transform2D::looking_at(const Vector2 &p_target) const {
Transform2D return_trans = Transform2D(get_rotation(), get_origin());
Vector2 target_position = affine_inverse().xform(p_target);
@@ -282,7 +286,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, const
real_t dot = v1.dot(v2);
- dot = CLAMP(dot, -1.0f, 1.0f);
+ dot = CLAMP(dot, (real_t)-1.0, (real_t)1.0);
Vector2 v;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index f23f32867a..2b11f36535 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -98,6 +98,7 @@ struct _NO_DISCARD_ Transform2D {
void orthonormalize();
Transform2D orthonormalized() const;
bool is_equal_approx(const Transform2D &p_transform) const;
+ bool is_finite() const;
Transform2D looking_at(const Vector2 &p_target) const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index 2de9e81b38..3285cbd664 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -31,7 +31,7 @@
#include "transform_3d.h"
#include "core/math/math_funcs.h"
-#include "core/string/print_string.h"
+#include "core/string/ustring.h"
void Transform3D::affine_invert() {
basis.invert();
@@ -174,6 +174,10 @@ bool Transform3D::is_equal_approx(const Transform3D &p_transform) const {
return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
}
+bool Transform3D::is_finite() const {
+ return basis.is_finite() && origin.is_finite();
+}
+
bool Transform3D::operator==(const Transform3D &p_transform) const {
return (basis == p_transform.basis && origin == p_transform.origin);
}
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index c62e4a7b0e..cb347aa1c1 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -34,6 +34,7 @@
#include "core/math/aabb.h"
#include "core/math/basis.h"
#include "core/math/plane.h"
+#include "core/templates/vector.h"
struct _NO_DISCARD_ Transform3D {
Basis basis;
@@ -74,6 +75,7 @@ struct _NO_DISCARD_ Transform3D {
void orthogonalize();
Transform3D orthogonalized() const;
bool is_equal_approx(const Transform3D &p_transform) const;
+ bool is_finite() const;
bool operator==(const Transform3D &p_transform) const;
bool operator!=(const Transform3D &p_transform) const;
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 4433559e6d..6515c55a85 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -215,10 +215,8 @@ Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const {
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects(p_aabb);
- if (!valid) {
+ if (!b.aabb.intersects(p_aabb)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
@@ -302,12 +300,8 @@ bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_en
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects_segment(p_begin, p_end);
- //bool valid = b.aabb.intersects(ray_aabb);
-
- if (!valid) {
+ if (!b.aabb.intersects_segment(p_begin, p_end)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
@@ -407,10 +401,8 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects_ray(p_begin, p_dir);
- if (!valid) {
+ if (!b.aabb.intersects_ray(p_begin, p_dir)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
@@ -508,10 +500,8 @@ bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_cou
switch (stack[level] >> VISITED_BIT_SHIFT) {
case TEST_AABB_BIT: {
- bool valid = b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count);
- if (!valid) {
+ if (!b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count)) {
stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
} else {
if (b.face_index >= 0) {
const Triangle &s = triangleptr[b.face_index];
diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp
index 56dbba393a..5366587126 100644
--- a/core/math/vector2.cpp
+++ b/core/math/vector2.cpp
@@ -186,6 +186,10 @@ bool Vector2::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y);
}
+bool Vector2::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y);
+}
+
Vector2::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
}
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 9441f84087..5775d8e735 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -69,10 +69,6 @@ struct _NO_DISCARD_ Vector2 {
return coord[p_idx];
}
- _FORCE_INLINE_ void set_all(const real_t p_value) {
- x = y = p_value;
- }
-
_FORCE_INLINE_ Vector2::Axis min_axis_index() const {
return x < y ? Vector2::AXIS_X : Vector2::AXIS_Y;
}
@@ -125,6 +121,7 @@ struct _NO_DISCARD_ Vector2 {
bool is_equal_approx(const Vector2 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
Vector2 operator+(const Vector2 &p_v) const;
void operator+=(const Vector2 &p_v);
diff --git a/core/math/vector2i.h b/core/math/vector2i.h
index 0245900a3b..e131bdea94 100644
--- a/core/math/vector2i.h
+++ b/core/math/vector2i.h
@@ -38,6 +38,8 @@ class String;
struct Vector2;
struct _NO_DISCARD_ Vector2i {
+ static const int AXIS_COUNT = 2;
+
enum Axis {
AXIS_X,
AXIS_Y,
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index 4db45fe798..b106200c4a 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -45,16 +45,6 @@ Vector3 Vector3::rotated(const Vector3 &p_axis, const real_t p_angle) const {
return r;
}
-void Vector3::set_axis(const int p_axis, const real_t p_value) {
- ERR_FAIL_INDEX(p_axis, 3);
- coord[p_axis] = p_value;
-}
-
-real_t Vector3::get_axis(const int p_axis) const {
- ERR_FAIL_INDEX_V(p_axis, 3, 0);
- return operator[](p_axis);
-}
-
Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const {
return Vector3(
CLAMP(x, p_min.x, p_max.x),
@@ -149,6 +139,10 @@ bool Vector3::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
}
+bool Vector3::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z);
+}
+
Vector3::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
}
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 3944afa92e..19771eb312 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -68,13 +68,6 @@ struct _NO_DISCARD_ Vector3 {
return coord[p_axis];
}
- void set_axis(const int p_axis, const real_t p_value);
- real_t get_axis(const int p_axis) const;
-
- _FORCE_INLINE_ void set_all(const real_t p_value) {
- x = y = z = p_value;
- }
-
_FORCE_INLINE_ Vector3::Axis min_axis_index() const {
return x < y ? (x < z ? Vector3::AXIS_X : Vector3::AXIS_Z) : (y < z ? Vector3::AXIS_Y : Vector3::AXIS_Z);
}
@@ -143,6 +136,7 @@ struct _NO_DISCARD_ Vector3 {
bool is_equal_approx(const Vector3 &p_v) const;
bool is_zero_approx() const;
+ bool is_finite() const;
/* Operators */
diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp
index b8e74ea6d2..b248f35035 100644
--- a/core/math/vector3i.cpp
+++ b/core/math/vector3i.cpp
@@ -33,16 +33,6 @@
#include "core/math/vector3.h"
#include "core/string/ustring.h"
-void Vector3i::set_axis(const int p_axis, const int32_t p_value) {
- ERR_FAIL_INDEX(p_axis, 3);
- coord[p_axis] = p_value;
-}
-
-int32_t Vector3i::get_axis(const int p_axis) const {
- ERR_FAIL_INDEX_V(p_axis, 3, 0);
- return operator[](p_axis);
-}
-
Vector3i::Axis Vector3i::min_axis_index() const {
return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z);
}
diff --git a/core/math/vector3i.h b/core/math/vector3i.h
index 825ce40318..710fd96376 100644
--- a/core/math/vector3i.h
+++ b/core/math/vector3i.h
@@ -38,6 +38,8 @@ class String;
struct Vector3;
struct _NO_DISCARD_ Vector3i {
+ static const int AXIS_COUNT = 3;
+
enum Axis {
AXIS_X,
AXIS_Y,
@@ -64,9 +66,6 @@ struct _NO_DISCARD_ Vector3i {
return coord[p_axis];
}
- void set_axis(const int p_axis, const int32_t p_value);
- int32_t get_axis(const int p_axis) const;
-
Vector3i::Axis min_axis_index() const;
Vector3i::Axis max_axis_index() const;
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index 3c25f454a3..3b189f7ed4 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -30,18 +30,7 @@
#include "vector4.h"
-#include "core/math/basis.h"
-#include "core/string/print_string.h"
-
-void Vector4::set_axis(const int p_axis, const real_t p_value) {
- ERR_FAIL_INDEX(p_axis, 4);
- components[p_axis] = p_value;
-}
-
-real_t Vector4::get_axis(const int p_axis) const {
- ERR_FAIL_INDEX_V(p_axis, 4, 0);
- return operator[](p_axis);
-}
+#include "core/string/ustring.h"
Vector4::Axis Vector4::min_axis_index() const {
uint32_t min_index = 0;
@@ -75,6 +64,10 @@ bool Vector4::is_zero_approx() const {
return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
}
+bool Vector4::is_finite() const {
+ return Math::is_finite(x) && Math::is_finite(y) && Math::is_finite(z) && Math::is_finite(w);
+}
+
real_t Vector4::length() const {
return Math::sqrt(length_squared());
}
diff --git a/core/math/vector4.h b/core/math/vector4.h
index f964264108..7c4bdc1788 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -31,12 +31,14 @@
#ifndef VECTOR4_H
#define VECTOR4_H
-#include "core/math/math_defs.h"
+#include "core/error/error_macros.h"
#include "core/math/math_funcs.h"
-#include "core/math/vector3.h"
-#include "core/string/ustring.h"
+
+class String;
struct _NO_DISCARD_ Vector4 {
+ static const int AXIS_COUNT = 4;
+
enum Axis {
AXIS_X,
AXIS_Y,
@@ -63,17 +65,13 @@ struct _NO_DISCARD_ Vector4 {
return components[p_axis];
}
- _FORCE_INLINE_ void set_all(const real_t p_value);
-
- void set_axis(const int p_axis, const real_t p_value);
- real_t get_axis(const int p_axis) const;
-
Vector4::Axis min_axis_index() const;
Vector4::Axis max_axis_index() const;
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
bool is_zero_approx() const;
+ bool is_finite() const;
real_t length() const;
void normalize();
Vector4 normalized() const;
@@ -148,10 +146,6 @@ struct _NO_DISCARD_ Vector4 {
}
};
-void Vector4::set_all(const real_t p_value) {
- x = y = z = p_value;
-}
-
real_t Vector4::dot(const Vector4 &p_vec4) const {
return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w;
}
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index a89b802675..77f6fbd5b7 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -33,16 +33,6 @@
#include "core/math/vector4.h"
#include "core/string/ustring.h"
-void Vector4i::set_axis(const int p_axis, const int32_t p_value) {
- ERR_FAIL_INDEX(p_axis, 4);
- coord[p_axis] = p_value;
-}
-
-int32_t Vector4i::get_axis(const int p_axis) const {
- ERR_FAIL_INDEX_V(p_axis, 4, 0);
- return operator[](p_axis);
-}
-
Vector4i::Axis Vector4i::min_axis_index() const {
uint32_t min_index = 0;
int32_t min_value = x;
diff --git a/core/math/vector4i.h b/core/math/vector4i.h
index d08e40d754..a32414bb18 100644
--- a/core/math/vector4i.h
+++ b/core/math/vector4i.h
@@ -38,6 +38,8 @@ class String;
struct Vector4;
struct _NO_DISCARD_ Vector4i {
+ static const int AXIS_COUNT = 4;
+
enum Axis {
AXIS_X,
AXIS_Y,
@@ -66,9 +68,6 @@ struct _NO_DISCARD_ Vector4i {
return coord[p_axis];
}
- void set_axis(const int p_axis, const int32_t p_value);
- int32_t get_axis(const int p_axis) const;
-
Vector4i::Axis min_axis_index() const;
Vector4i::Axis max_axis_index() const;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index 99b20560da..ac6ad0fdd2 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -31,6 +31,7 @@
#include "class_db.h"
#include "core/config/engine.h"
+#include "core/object/script_language.h"
#include "core/os/mutex.h"
#include "core/version.h"
@@ -376,7 +377,12 @@ bool ClassDB::is_virtual(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ if (!ti) {
+ if (!ScriptServer::is_global_class(p_class)) {
+ ERR_FAIL_V_MSG(false, "Cannot get class '" + String(p_class) + "'.");
+ }
+ return false;
+ }
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
return false;
@@ -1454,7 +1460,7 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con
if (Engine::get_singleton()->has_singleton(p_class)) {
c = Engine::get_singleton()->get_singleton_object(p_class);
cleanup_c = false;
- } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) {
+ } else if (ClassDB::can_instantiate(p_class) && !ClassDB::is_virtual(p_class)) { // Keep this condition in sync with doc_tools.cpp get_documentation_default_value.
c = ClassDB::instantiate(p_class);
cleanup_c = true;
}
@@ -1528,7 +1534,10 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION;
c.native_extension = p_extension;
c.name = p_extension->class_name;
- c.creation_func = parent->creation_func;
+ c.is_virtual = p_extension->is_virtual;
+ if (!p_extension->is_abstract) {
+ c.creation_func = parent->creation_func;
+ }
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
@@ -1538,7 +1547,11 @@ void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) {
}
void ClassDB::unregister_extension_class(const StringName &p_class) {
- ERR_FAIL_COND(!classes.has(p_class));
+ ClassInfo *c = classes.getptr(p_class);
+ ERR_FAIL_COND_MSG(!c, "Class " + p_class + "does not exist");
+ for (KeyValue<StringName, MethodBind *> &F : c->method_map) {
+ memdelete(F.value);
+ }
classes.erase(p_class);
}
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index c18d70d9f6..61bf6d900a 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -5,18 +5,19 @@ mutable bool _gdvirtual_##m_name##_initialized = false;\\
mutable GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
- ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
- if (script_instance) {\\
+ ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\
+ if (_script_instance) {\\
Callable::CallError ce; \\
$CALLSIARGS\\
- $CALLSIBEGINscript_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
+ $CALLSIBEGIN_script_instance->callp(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\
if (ce.error == Callable::CallError::CALL_OK) {\\
$CALLSIRET\\
return true;\\
} \\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ /* TODO: C-style cast because GDNativeStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDNativeStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDNativeExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
@@ -35,12 +36,13 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
return false;\\
}\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\
- ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\
- if (script_instance) {\\
- return script_instance->has_method(_gdvirtual_##m_name##_sn);\\
+ ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\
+ if (_script_instance) {\\
+ return _script_instance->has_method(_gdvirtual_##m_name##_sn);\\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\
+ /* TODO: C-style cast because GDNativeStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
+ _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDNativeStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDNativeExtensionClassCallVirtual) nullptr;\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index 0edc7a90c2..5381c596ce 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -63,7 +63,9 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo info = _gen_argument_type_info(p_argument);
#ifdef DEBUG_METHODS_ENABLED
- info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ if (info.name.is_empty()) {
+ info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
+ }
#endif
return info;
}
diff --git a/core/object/method_bind.h b/core/object/method_bind.h
index d60550c899..598e8a224d 100644
--- a/core/object/method_bind.h
+++ b/core/object/method_bind.h
@@ -241,9 +241,17 @@ class MethodBindVarArgTR : public MethodBindVarArgBase<MethodBindVarArgTR<T, R>,
friend class MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>;
public:
+#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+ // Workaround GH-66343 raised only with UBSAN, seems to be a false positive.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) override {
return (static_cast<T *>(p_object)->*MethodBindVarArgBase<MethodBindVarArgTR<T, R>, T, R, true>::method)(p_args, p_arg_count, r_error);
}
+#if defined(SANITIZERS_ENABLED) && defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
MethodBindVarArgTR(
R (T::*p_method)(const Variant **, int, Callable::CallError &),
@@ -284,11 +292,6 @@ class MethodBindT : public MethodBind {
void (MB_T::*method)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -296,9 +299,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -359,11 +359,6 @@ class MethodBindTC : public MethodBind {
void (MB_T::*method)(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -371,9 +366,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -436,11 +428,6 @@ class MethodBindTR : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -458,9 +445,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -523,11 +507,6 @@ class MethodBindTRC : public MethodBind {
(P...) const;
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -545,9 +524,6 @@ protected:
return GetTypeInfo<R>::get_class_info();
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
public:
#ifdef DEBUG_METHODS_ENABLED
@@ -607,11 +583,6 @@ class MethodBindTS : public MethodBind {
void (*function)(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -619,9 +590,6 @@ protected:
return Variant::NIL;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
PropertyInfo pi;
@@ -670,11 +638,6 @@ class MethodBindTRS : public MethodBind {
(P...);
protected:
-// GCC raises warnings in the case P = {} as the comparison is always false...
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wlogical-op"
-#endif
virtual Variant::Type _gen_argument_type(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
return call_get_argument_type<P...>(p_arg);
@@ -682,9 +645,6 @@ protected:
return GetTypeInfo<R>::VARIANT_TYPE;
}
}
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
virtual PropertyInfo _gen_argument_type_info(int p_arg) const override {
if (p_arg >= 0 && p_arg < (int)sizeof...(P)) {
diff --git a/core/object/object.cpp b/core/object/object.cpp
index c275164b14..d27e0d7621 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -808,7 +808,8 @@ String Object::to_string() {
}
if (_extension && _extension->to_string) {
String ret;
- _extension->to_string(_extension_instance, &ret);
+ GDNativeBool is_valid;
+ _extension->to_string(_extension_instance, &is_valid, &ret);
return ret;
}
return "<" + get_class() + "#" + itos(get_instance_id()) + ">";
@@ -1468,8 +1469,8 @@ void Object::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_class", "class"), &Object::is_class);
ClassDB::bind_method(D_METHOD("set", "property", "value"), &Object::_set_bind);
ClassDB::bind_method(D_METHOD("get", "property"), &Object::_get_bind);
- ClassDB::bind_method(D_METHOD("set_indexed", "property", "value"), &Object::_set_indexed_bind);
- ClassDB::bind_method(D_METHOD("get_indexed", "property"), &Object::_get_indexed_bind);
+ ClassDB::bind_method(D_METHOD("set_indexed", "property_path", "value"), &Object::_set_indexed_bind);
+ ClassDB::bind_method(D_METHOD("get_indexed", "property_path"), &Object::_get_indexed_bind);
ClassDB::bind_method(D_METHOD("get_property_list"), &Object::_get_property_list_bind);
ClassDB::bind_method(D_METHOD("get_method_list"), &Object::_get_method_list_bind);
ClassDB::bind_method(D_METHOD("notification", "what", "reversed"), &Object::notification, DEFVAL(false));
@@ -1856,6 +1857,46 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
}
void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
+ if (p_idx == 0) {
+ if (p_function == "connect" || p_function == "is_connected" || p_function == "disconnect" || p_function == "emit_signal" || p_function == "has_signal") {
+ List<MethodInfo> signals;
+ get_signal_list(&signals);
+ for (const MethodInfo &E : signals) {
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "call" || p_function == "call_deferred" || p_function == "callv" || p_function == "has_method") {
+ List<MethodInfo> methods;
+ get_method_list(&methods);
+ for (const MethodInfo &E : methods) {
+ if (E.name.begins_with("_") && !(E.flags & METHOD_FLAG_VIRTUAL)) {
+ continue;
+ }
+ r_options->push_back(E.name.quote());
+ }
+ } else if (p_function == "set" || p_function == "set_deferred" || p_function == "get") {
+ List<PropertyInfo> properties;
+ get_property_list(&properties);
+ for (const PropertyInfo &E : properties) {
+ if (E.usage & PROPERTY_USAGE_DEFAULT && !(E.usage & PROPERTY_USAGE_INTERNAL)) {
+ r_options->push_back(E.name.quote());
+ }
+ }
+ } else if (p_function == "set_meta" || p_function == "get_meta" || p_function == "has_meta" || p_function == "remove_meta") {
+ for (const KeyValue<StringName, Variant> &K : metadata) {
+ r_options->push_back(String(K.key).quote());
+ }
+ }
+ } else if (p_idx == 2) {
+ if (p_function == "connect") {
+ // Ideally, the constants should be inferred by the parameter.
+ // But a parameter's PropertyInfo does not store the enum they come from, so this will do for now.
+ List<StringName> constants;
+ ClassDB::get_enum_constants("Object", "ConnectFlags", &constants);
+ for (const StringName &E : constants) {
+ r_options->push_back(String(E));
+ }
+ }
+ }
}
SpinLock ObjectDB::spin_lock;
diff --git a/core/object/object.h b/core/object/object.h
index 8ade5a204a..16ad7b8832 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -50,7 +50,7 @@ class TypedArray;
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_less][,hide_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only")
@@ -71,8 +71,6 @@ enum PropertyHint {
PROPERTY_HINT_EXPRESSION, ///< used for string properties that can contain multiple lines
PROPERTY_HINT_PLACEHOLDER_TEXT, ///< used to set a placeholder text for string properties
PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
- PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
- PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
PROPERTY_HINT_OBJECT_ID,
PROPERTY_HINT_TYPE_STRING, ///< a type string, the hint is the base type to choose
PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE, ///< so something else can provide this (used in scripts)
@@ -89,8 +87,8 @@ enum PropertyHint {
PROPERTY_HINT_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_GLOBAL_SAVE_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,". This opens a save dialog
PROPERTY_HINT_INT_IS_OBJECTID,
- PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_INT_IS_POINTER,
+ PROPERTY_HINT_ARRAY_TYPE,
PROPERTY_HINT_LOCALE_ID,
PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_NODE_TYPE, ///< a node object type
@@ -133,7 +131,7 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_ARRAY = 1 << 29, // Used in the inspector to group properties as elements of an array.
PROPERTY_USAGE_DEFAULT = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR,
- PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNATIONALIZED,
+ PROPERTY_USAGE_DEFAULT_INTL = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNATIONALIZED,
PROPERTY_USAGE_NO_EDITOR = PROPERTY_USAGE_STORAGE,
};
@@ -192,10 +190,10 @@ struct PropertyInfo {
explicit PropertyInfo(const GDNativePropertyInfo &pinfo) :
type((Variant::Type)pinfo.type),
- name(pinfo.name),
- class_name(pinfo.class_name), // can be null
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ class_name(*reinterpret_cast<StringName *>(pinfo.class_name)),
hint((PropertyHint)pinfo.hint),
- hint_string(pinfo.hint_string), // can be null
+ hint_string(*reinterpret_cast<String *>(pinfo.hint_string)),
usage(pinfo.usage) {}
bool operator==(const PropertyInfo &p_info) const {
@@ -242,6 +240,20 @@ struct MethodInfo {
MethodInfo() {}
+ explicit MethodInfo(const GDNativeMethodInfo &pinfo) :
+ name(*reinterpret_cast<StringName *>(pinfo.name)),
+ return_val(PropertyInfo(pinfo.return_value)),
+ flags(pinfo.flags),
+ id(pinfo.id) {
+ for (uint32_t j = 0; j < pinfo.argument_count; j++) {
+ arguments.push_back(PropertyInfo(pinfo.arguments[j]));
+ }
+ const Variant *def_values = (const Variant *)pinfo.default_arguments;
+ for (uint32_t j = 0; j < pinfo.default_argument_count; j++) {
+ default_arguments.push_back(def_values[j]);
+ }
+ }
+
void _push_params(const PropertyInfo &p_param) {
arguments.push_back(p_param);
}
@@ -295,6 +307,8 @@ struct ObjectNativeExtension {
StringName parent_class_name;
StringName class_name;
bool editor_class = false;
+ bool is_virtual = false;
+ bool is_abstract = false;
GDNativeExtensionClassSet set;
GDNativeExtensionClassGet get;
GDNativeExtensionClassGetPropertyList get_property_list;
@@ -733,34 +747,12 @@ public:
template <class T>
static T *cast_to(Object *p_object) {
-#ifndef NO_SAFE_CAST
return dynamic_cast<T *>(p_object);
-#else
- if (!p_object) {
- return nullptr;
- }
- if (p_object->is_class_ptr(T::get_class_ptr_static())) {
- return static_cast<T *>(p_object);
- } else {
- return nullptr;
- }
-#endif
}
template <class T>
static const T *cast_to(const Object *p_object) {
-#ifndef NO_SAFE_CAST
return dynamic_cast<const T *>(p_object);
-#else
- if (!p_object) {
- return nullptr;
- }
- if (p_object->is_class_ptr(T::get_class_ptr_static())) {
- return static_cast<const T *>(p_object);
- } else {
- return nullptr;
- }
-#endif
}
enum {
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index cac2400744..50467d795d 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -48,9 +48,10 @@ void RefCounted::_bind_methods() {
ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref);
ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference);
ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference);
+ ClassDB::bind_method(D_METHOD("get_reference_count"), &RefCounted::get_reference_count);
}
-int RefCounted::reference_get_count() const {
+int RefCounted::get_reference_count() const {
return refcount.get();
}
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index bd06a84bd8..71790fb825 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -47,7 +47,7 @@ public:
bool init_ref();
bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference();
- int reference_get_count() const;
+ int get_reference_count() const;
RefCounted();
~RefCounted() {}
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index e56d2e80b9..056c57a5f1 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -106,23 +106,23 @@ Dictionary Script::_get_script_constant_map() {
PropertyInfo Script::get_class_category() const {
String path = get_path();
- String name;
+ String scr_name;
if (is_built_in()) {
if (get_name().is_empty()) {
- name = TTR("Built-in script");
+ scr_name = TTR("Built-in script");
} else {
- name = vformat("%s (%s)", get_name(), TTR("Built-in"));
+ scr_name = vformat("%s (%s)", get_name(), TTR("Built-in"));
}
} else {
if (get_name().is_empty()) {
- name = path.get_file();
+ scr_name = path.get_file();
} else {
- name = get_name();
+ scr_name = get_name();
}
}
- return PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
+ return PropertyInfo(Variant::NIL, scr_name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
}
#endif // TOOLS_ENABLED
@@ -166,6 +166,7 @@ ScriptLanguage *ScriptServer::get_language(int p_idx) {
}
void ScriptServer::register_language(ScriptLanguage *p_language) {
+ ERR_FAIL_NULL(p_language);
ERR_FAIL_COND(_language_count >= MAX_LANGUAGES);
_languages[_language_count++] = p_language;
}
@@ -183,10 +184,10 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
}
void ScriptServer::init_languages() {
- { //load global classes
+ { // Load global classes.
global_classes_clear();
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
+ Array script_classes = GLOBAL_GET("_global_script_classes");
for (int i = 0; i < script_classes.size(); i++) {
Dictionary c = script_classes[i];
@@ -304,7 +305,7 @@ void ScriptServer::save_global_classes() {
Array old;
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- old = ProjectSettings::get_singleton()->get("_global_script_classes");
+ old = GLOBAL_GET("_global_script_classes");
}
if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
return;
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 7e74f6a2be..9a2a176096 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -82,9 +82,10 @@ public:
GDVIRTUAL_REQUIRED_CALL(_get_documentation, doc);
Vector<DocData::ClassDoc> class_doc;
-#ifndef _MSC_VER
-#warning missing conversion from documentation to ClassDoc
-#endif
+ for (int i = 0; i < doc.size(); i++) {
+ class_doc.append(DocData::ClassDoc::from_dict(doc[i]));
+ }
+
return class_doc;
}
#endif // TOOLS_ENABLED
@@ -686,7 +687,6 @@ public:
if (r_is_valid) {
*r_is_valid = is_valid != 0;
}
-
return Variant::Type(type);
}
return Variant::NIL;
@@ -726,19 +726,7 @@ public:
uint32_t mcount;
const GDNativeMethodInfo *minfo = native_info->get_method_list_func(instance, &mcount);
for (uint32_t i = 0; i < mcount; i++) {
- MethodInfo m;
- m.name = minfo[i].name;
- m.flags = minfo[i].flags;
- m.id = minfo[i].id;
- m.return_val = PropertyInfo(minfo[i].return_value);
- for (uint32_t j = 0; j < minfo[i].argument_count; j++) {
- m.arguments.push_back(PropertyInfo(minfo[i].arguments[j]));
- }
- const Variant *def_values = (const Variant *)minfo[i].default_arguments;
- for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) {
- m.default_arguments.push_back(def_values[j]);
- }
- p_list->push_back(m);
+ p_list->push_back(MethodInfo(minfo[i]));
}
if (native_info->free_method_list_func) {
native_info->free_method_list_func(instance, minfo);
@@ -772,7 +760,8 @@ public:
virtual String to_string(bool *r_valid) override {
if (native_info->to_string_func) {
GDNativeBool valid;
- String ret = native_info->to_string_func(instance, &valid);
+ String ret;
+ native_info->to_string_func(instance, &valid, reinterpret_cast<GDNativeStringPtr>(&ret));
if (r_valid) {
*r_valid = valid != 0;
}
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index aa66e86bc0..9f8a1de697 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -423,6 +423,10 @@ String UndoRedo::get_current_action_name() const {
return actions[current_action].name;
}
+int UndoRedo::get_action_level() const {
+ return action_level;
+}
+
bool UndoRedo::has_undo() const {
return current_action >= 0;
}
diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h
index c7c58697c3..9c6d2d10ed 100644
--- a/core/object/undo_redo.h
+++ b/core/object/undo_redo.h
@@ -120,6 +120,7 @@ public:
bool redo();
bool undo();
String get_current_action_name() const;
+ int get_action_level() const;
int get_history_count();
int get_current_action();
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index c770515b9e..9b3dc6833e 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -395,7 +395,7 @@ void WorkerThreadPool::wait_for_group_task_completion(GroupID p_group) {
uint32_t finished_users = group->finished.increment(); // fetch happens before inc, so increment later.
if (finished_users == max_users) {
- // All tasks using this group are gone (finished before the group), so clear the gorup too.
+ // All tasks using this group are gone (finished before the group), so clear the group too.
task_mutex.lock();
group_allocator.free(group);
task_mutex.unlock();
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index a96e1989f9..c0504a174c 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -65,21 +65,15 @@ void MainLoop::initialize() {
}
bool MainLoop::physics_process(double p_time) {
- bool quit;
- if (GDVIRTUAL_CALL(_physics_process, p_time, quit)) {
- return quit;
- }
-
- return false;
+ bool quit = false;
+ GDVIRTUAL_CALL(_physics_process, p_time, quit);
+ return quit;
}
bool MainLoop::process(double p_time) {
- bool quit;
- if (GDVIRTUAL_CALL(_process, p_time, quit)) {
- return quit;
- }
-
- return false;
+ bool quit = false;
+ GDVIRTUAL_CALL(_process, p_time, quit);
+ return quit;
}
void MainLoop::finalize() {
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
index 410b62068a..79eef95ef2 100644
--- a/core/os/midi_driver.cpp
+++ b/core/os/midi_driver.cpp
@@ -86,11 +86,6 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_
if (length >= 2 + param_position) {
event->set_pitch(data[param_position]);
event->set_velocity(data[param_position + 1]);
-
- if (event->get_message() == MIDIMessage::NOTE_ON && event->get_velocity() == 0) {
- // https://www.midi.org/forum/228-writing-midi-software-send-note-off,-or-zero-velocity-note-on
- event->set_message(MIDIMessage::NOTE_OFF);
- }
}
break;
diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp
index 1d4400bfc1..512db1737a 100644
--- a/core/os/mutex.cpp
+++ b/core/os/mutex.cpp
@@ -40,11 +40,7 @@ void _global_unlock() {
_global_mutex.unlock();
}
-#ifndef NO_THREADS
-
template class MutexImpl<std::recursive_mutex>;
template class MutexImpl<std::mutex>;
template class MutexLock<MutexImpl<std::recursive_mutex>>;
template class MutexLock<MutexImpl<std::mutex>>;
-
-#endif
diff --git a/core/os/mutex.h b/core/os/mutex.h
index a51248807b..eb58418bd6 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -34,8 +34,6 @@
#include "core/error/error_list.h"
#include "core/typedefs.h"
-#if !defined(NO_THREADS)
-
#include <mutex>
template <class StdMutexT>
@@ -79,29 +77,4 @@ extern template class MutexImpl<std::mutex>;
extern template class MutexLock<MutexImpl<std::recursive_mutex>>;
extern template class MutexLock<MutexImpl<std::mutex>>;
-#else
-
-class FakeMutex {
- FakeMutex() {}
-};
-
-template <class MutexT>
-class MutexImpl {
-public:
- _ALWAYS_INLINE_ void lock() const {}
- _ALWAYS_INLINE_ void unlock() const {}
- _ALWAYS_INLINE_ Error try_lock() const { return OK; }
-};
-
-template <class MutexT>
-class MutexLock {
-public:
- explicit MutexLock(const MutexT &p_mutex) {}
-};
-
-using Mutex = MutexImpl<FakeMutex>;
-using BinaryMutex = MutexImpl<FakeMutex>; // Non-recursive, handle with care
-
-#endif // !NO_THREADS
-
#endif // MUTEX_H
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 526b31ae7e..bbb2a94fe7 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -38,6 +38,7 @@
#include "core/version_generated.gen.h"
#include <stdarg.h>
+#include <thread>
OS *OS::singleton = nullptr;
uint64_t OS::target_ticks = 0;
@@ -54,10 +55,6 @@ double OS::get_unix_time() const {
return 0;
}
-void OS::debug_break() {
- // something
-}
-
void OS::_set_logger(CompositeLogger *p_logger) {
if (_logger) {
memdelete(_logger);
@@ -325,21 +322,13 @@ String OS::get_unique_id() const {
}
int OS::get_processor_count() const {
- return 1;
+ return std::thread::hardware_concurrency();
}
String OS::get_processor_name() const {
return "";
}
-bool OS::can_use_threads() const {
-#ifdef NO_THREADS
- return false;
-#else
- return true;
-#endif
-}
-
void OS::set_has_server_feature_callback(HasServerFeatureCallback p_callback) {
has_server_feature_callback = p_callback;
}
@@ -523,10 +512,10 @@ void OS::add_frame_delay(bool p_can_draw) {
if (is_in_low_processor_usage_mode() || !p_can_draw) {
dynamic_delay = get_low_processor_usage_mode_sleep_usec();
}
- const int target_fps = Engine::get_singleton()->get_target_fps();
- if (target_fps > 0 && !Engine::get_singleton()->is_editor_hint()) {
+ const int max_fps = Engine::get_singleton()->get_max_fps();
+ if (max_fps > 0 && !Engine::get_singleton()->is_editor_hint()) {
// Override the low processor usage mode sleep delay if the target FPS is lower.
- dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / target_fps));
+ dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / max_fps));
}
if (dynamic_delay > 0) {
diff --git a/core/os/os.h b/core/os/os.h
index 6944d29eeb..af7b40f3ec 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -69,6 +69,7 @@ class OS {
// so we can retrieve the rendering drivers available
int _display_driver_id = -1;
String _current_rendering_driver_name;
+ String _current_rendering_method;
protected:
void _set_logger(CompositeLogger *p_logger);
@@ -98,6 +99,8 @@ protected:
virtual void initialize_joypads() = 0;
void set_current_rendering_driver_name(String p_driver_name) { _current_rendering_driver_name = p_driver_name; }
+ void set_current_rendering_method(String p_name) { _current_rendering_method = p_name; }
+
void set_display_driver_id(int p_display_driver_id) { _display_driver_id = p_display_driver_id; }
virtual void set_main_loop(MainLoop *p_main_loop) = 0;
@@ -116,8 +119,12 @@ public:
static OS *get_singleton();
String get_current_rendering_driver_name() const { return _current_rendering_driver_name; }
+ String get_current_rendering_method() const { return _current_rendering_method; }
+
int get_display_driver_id() const { return _display_driver_id; }
+ virtual Vector<String> get_video_adapter_driver_info() const = 0;
+
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR);
void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void print_rich(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
@@ -282,8 +289,6 @@ public:
virtual Error move_to_trash(const String &p_path) { return FAILED; }
- virtual void debug_break();
-
virtual int get_exit_code() const;
// `set_exit_code` should only be used from `SceneTree` (or from a similar
// level, e.g. from the `Main::start` if leaving without creating a `SceneTree`).
@@ -296,8 +301,6 @@ public:
virtual String get_unique_id() const;
- virtual bool can_use_threads() const;
-
bool has_feature(const String &p_feature);
void set_has_server_feature_callback(HasServerFeatureCallback p_callback);
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index f622e2c7c5..e7f2cff7c5 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -35,8 +35,6 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include <assert.h>
-
#define COMPACT_CHUNK(m_entry, m_to_pos) \
do { \
void *_dst = &((unsigned char *)pool)[m_to_pos]; \
@@ -169,11 +167,6 @@ bool PoolAllocator::find_entry_index(EntryIndicesPos *p_map_pos, const Entry *p_
PoolAllocator::ID PoolAllocator::alloc(int p_size) {
ERR_FAIL_COND_V(p_size < 1, POOL_ALLOCATOR_INVALID_ID);
-#ifdef DEBUG_ENABLED
- if (p_size > free_mem) {
- OS::get_singleton()->debug_break();
- }
-#endif
ERR_FAIL_COND_V(p_size > free_mem, POOL_ALLOCATOR_INVALID_ID);
mt_lock();
@@ -482,7 +475,6 @@ void *PoolAllocator::get(ID p_mem) {
ERR_FAIL_COND_V(!e, nullptr);
}
if (e->lock == 0) {
- //assert(0);
mt_unlock();
ERR_PRINT("e->lock == 0");
return nullptr;
diff --git a/core/os/rw_lock.h b/core/os/rw_lock.h
index a046f474ea..d3206547c7 100644
--- a/core/os/rw_lock.h
+++ b/core/os/rw_lock.h
@@ -33,8 +33,6 @@
#include "core/error/error_list.h"
-#if !defined(NO_THREADS)
-
#include <shared_mutex>
class RWLock {
@@ -72,21 +70,6 @@ public:
}
};
-#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 {
const RWLock &lock;
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index 72df52dd34..1a93d3ee2c 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -34,8 +34,6 @@
#include "core/error/error_list.h"
#include "core/typedefs.h"
-#if !defined(NO_THREADS)
-
#include <condition_variable>
#include <mutex>
@@ -70,15 +68,4 @@ public:
}
};
-#else
-
-class Semaphore {
-public:
- _ALWAYS_INLINE_ void post() const {}
- _ALWAYS_INLINE_ void wait() const {}
- _ALWAYS_INLINE_ bool try_wait() const { return true; }
-};
-
-#endif
-
#endif // SEMAPHORE_H
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index c8072b7280..712f4793eb 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -34,15 +34,9 @@
#include "thread.h"
#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;
+Thread::PlatformFunctions Thread::platform_functions;
uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) {
static std::hash<std::thread::id> hasher;
@@ -52,30 +46,27 @@ uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) {
Thread::ID Thread::main_thread_id = _thread_id_hash(std::this_thread::get_id());
thread_local Thread::ID Thread::caller_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;
+void Thread::_set_platform_functions(const PlatformFunctions &p_functions) {
+ platform_functions = p_functions;
}
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 (platform_functions.set_priority) {
+ platform_functions.set_priority(p_settings.priority);
}
- if (init_func) {
- init_func();
+ if (platform_functions.init) {
+ platform_functions.init();
+ }
+ ScriptServer::thread_enter(); // Scripts may need to attach a stack.
+ if (platform_functions.wrapper) {
+ platform_functions.wrapper(p_callback, p_userdata);
+ } else {
+ p_callback(p_userdata);
}
- ScriptServer::thread_enter(); //scripts may need to attach a stack
- p_callback(p_userdata);
ScriptServer::thread_exit();
- if (term_func) {
- term_func();
+ if (platform_functions.term) {
+ platform_functions.term();
}
}
@@ -108,8 +99,8 @@ void Thread::wait_to_finish() {
}
Error Thread::set_name(const String &p_name) {
- if (set_name_func) {
- return set_name_func(p_name);
+ if (platform_functions.set_name) {
+ return platform_functions.set_name(p_name);
}
return ERR_UNAVAILABLE;
@@ -128,5 +119,4 @@ Thread::~Thread() {
}
}
-#endif
#endif // PLATFORM_THREAD_OVERRIDE
diff --git a/core/os/thread.h b/core/os/thread.h
index 0fb283e224..86442de760 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -35,15 +35,14 @@
#ifdef PLATFORM_THREAD_OVERRIDE
#include "platform_thread.h"
#else
+
#ifndef THREAD_H
#define THREAD_H
+#include "core/templates/safe_refcount.h"
#include "core/typedefs.h"
-#if !defined(NO_THREADS)
-#include "core/templates/safe_refcount.h"
#include <thread>
-#endif
class String;
@@ -64,8 +63,15 @@ public:
Settings() { priority = PRIORITY_NORMAL; }
};
+ struct PlatformFunctions {
+ Error (*set_name)(const String &) = nullptr;
+ void (*set_priority)(Thread::Priority) = nullptr;
+ void (*init)() = nullptr;
+ void (*wrapper)(Thread::Callback, void *) = nullptr;
+ void (*term)() = nullptr;
+ };
+
private:
-#if !defined(NO_THREADS)
friend class Main;
static ID main_thread_id;
@@ -78,20 +84,11 @@ private:
static void callback(Thread *p_self, const Settings &p_settings, Thread::Callback p_callback, void *p_userdata);
- static Error (*set_name_func)(const String &);
- static void (*set_priority_func)(Thread::Priority);
- static void (*init_func)();
- static void (*term_func)();
-#endif
+ static PlatformFunctions platform_functions;
public:
- 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);
+ static void _set_platform_functions(const PlatformFunctions &p_functions);
-#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; }
@@ -107,19 +104,6 @@ public:
Thread();
~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/threaded_array_processor.h b/core/os/threaded_array_processor.h
index 935fc7a360..95a2253f14 100644
--- a/core/os/threaded_array_processor.h
+++ b/core/os/threaded_array_processor.h
@@ -49,8 +49,6 @@ struct ThreadArrayProcessData {
}
};
-#ifndef NO_THREADS
-
template <class T>
void process_array_thread(void *ud) {
T &data = *(T *)ud;
@@ -86,21 +84,4 @@ void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_us
memdelete_arr(threads);
}
-#else
-
-template <class C, class M, class U>
-void thread_process_array(uint32_t p_elements, C *p_instance, M p_method, U p_userdata) {
- ThreadArrayProcessData<C, U> data;
- data.method = p_method;
- data.instance = p_instance;
- data.userdata = p_userdata;
- data.index.set(0);
- data.elements = p_elements;
- for (uint32_t i = 0; i < p_elements; i++) {
- data.process(i);
- }
-}
-
-#endif
-
#endif // THREADED_ARRAY_PROCESSOR_H
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 6dfb0f82e0..2e144a4c9a 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -44,6 +44,7 @@
#include "core/input/input_map.h"
#include "core/input/shortcut.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
#include "core/io/dtls_server.h"
#include "core/io/http_client.h"
#include "core/io/image_loader.h"
@@ -58,6 +59,7 @@
#include "core/io/resource_format_binary.h"
#include "core/io/resource_importer.h"
#include "core/io/resource_uid.h"
+#include "core/io/stream_peer_gzip.h"
#include "core/io/stream_peer_tls.h"
#include "core/io/tcp_server.h"
#include "core/io/translation_loader_po.h"
@@ -184,6 +186,7 @@ void register_core_types() {
GDREGISTER_ABSTRACT_CLASS(StreamPeer);
GDREGISTER_CLASS(StreamPeerExtension);
GDREGISTER_CLASS(StreamPeerBuffer);
+ GDREGISTER_CLASS(StreamPeerGZIP);
GDREGISTER_CLASS(StreamPeerTCP);
GDREGISTER_CLASS(TCPServer);
@@ -228,8 +231,8 @@ void register_core_types() {
GDREGISTER_CLASS(ResourceFormatLoader);
GDREGISTER_CLASS(ResourceFormatSaver);
- GDREGISTER_CLASS(core_bind::File);
- GDREGISTER_CLASS(core_bind::Directory);
+ GDREGISTER_ABSTRACT_CLASS(FileAccess);
+ GDREGISTER_ABSTRACT_CLASS(DirAccess);
GDREGISTER_CLASS(core_bind::Thread);
GDREGISTER_CLASS(core_bind::Mutex);
GDREGISTER_CLASS(core_bind::Semaphore);
@@ -249,6 +252,8 @@ void register_core_types() {
GDREGISTER_CLASS(EncodedObjectAsID);
GDREGISTER_CLASS(RandomNumberGenerator);
+ GDREGISTER_ABSTRACT_CLASS(ImageFormatLoader);
+ GDREGISTER_CLASS(ImageFormatLoaderExtension);
GDREGISTER_ABSTRACT_CLASS(ResourceImporter);
GDREGISTER_CLASS(NativeExtension);
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index 07302cc8c3..2fb3b54e27 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -179,14 +179,14 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) {
}
bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name.operator String();
- if (name == "hash_table") {
+ String prop_name = p_name.operator String();
+ if (prop_name == "hash_table") {
hash_table = p_value;
- } else if (name == "bucket_table") {
+ } else if (prop_name == "bucket_table") {
bucket_table = p_value;
- } else if (name == "strings") {
+ } else if (prop_name == "strings") {
strings = p_value;
- } else if (name == "load_from") {
+ } else if (prop_name == "load_from") {
generate(p_value);
} else {
return false;
@@ -196,12 +196,12 @@ bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value
}
bool OptimizedTranslation::_get(const StringName &p_name, Variant &r_ret) const {
- String name = p_name.operator String();
- if (name == "hash_table") {
+ String prop_name = p_name.operator String();
+ if (prop_name == "hash_table") {
r_ret = hash_table;
- } else if (name == "bucket_table") {
+ } else if (prop_name == "bucket_table") {
r_ret = bucket_table;
- } else if (name == "strings") {
+ } else if (prop_name == "strings") {
r_ret = strings;
} else {
return false;
@@ -267,6 +267,39 @@ StringName OptimizedTranslation::get_message(const StringName &p_src_text, const
}
}
+Vector<String> OptimizedTranslation::get_translated_message_list() const {
+ Vector<String> msgs;
+
+ const int *htr = hash_table.ptr();
+ const uint32_t *htptr = (const uint32_t *)&htr[0];
+ const int *btr = bucket_table.ptr();
+ const uint32_t *btptr = (const uint32_t *)&btr[0];
+ const uint8_t *sr = strings.ptr();
+ const char *sptr = (const char *)&sr[0];
+
+ for (int i = 0; i < hash_table.size(); i++) {
+ uint32_t p = htptr[i];
+ if (p != 0xFFFFFFFF) {
+ const Bucket &bucket = *(const Bucket *)&btptr[p];
+ for (int j = 0; j < bucket.size; j++) {
+ if (bucket.elem[j].comp_size == bucket.elem[j].uncomp_size) {
+ String rstr;
+ rstr.parse_utf8(&sptr[bucket.elem[j].str_offset], bucket.elem[j].uncomp_size);
+ msgs.push_back(rstr);
+ } else {
+ CharString uncomp;
+ uncomp.resize(bucket.elem[j].uncomp_size + 1);
+ smaz_decompress(&sptr[bucket.elem[j].str_offset], bucket.elem[j].comp_size, uncomp.ptrw(), bucket.elem[j].uncomp_size);
+ String rstr;
+ rstr.parse_utf8(uncomp.get_data());
+ msgs.push_back(rstr);
+ }
+ }
+ }
+ }
+ return msgs;
+}
+
StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const {
// The use of plurals translation is not yet supported in OptimizedTranslation.
return get_message(p_src_text, p_context);
diff --git a/core/string/optimized_translation.h b/core/string/optimized_translation.h
index f3dbfe8f5c..1cd12782d0 100644
--- a/core/string/optimized_translation.h
+++ b/core/string/optimized_translation.h
@@ -81,6 +81,7 @@ protected:
public:
virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations
virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override;
+ virtual Vector<String> get_translated_message_list() const override;
void generate(const Ref<Translation> &p_from);
OptimizedTranslation() {}
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 4748f1a0cb..d1ac91957a 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -59,6 +59,18 @@ Vector<String> Translation::_get_message_list() const {
return msgs;
}
+Vector<String> Translation::get_translated_message_list() const {
+ Vector<String> msgs;
+ msgs.resize(translation_map.size());
+ int idx = 0;
+ for (const KeyValue<StringName, StringName> &E : translation_map) {
+ msgs.set(idx, E.value);
+ idx += 1;
+ }
+
+ return msgs;
+}
+
void Translation::_set_messages(const Dictionary &p_messages) {
List<Variant> keys;
p_messages.get_key_list(&keys);
@@ -140,6 +152,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_plural_message", "src_message", "src_plural_message", "n", "context"), &Translation::get_plural_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
+ ClassDB::bind_method(D_METHOD("get_translated_message_list"), &Translation::get_translated_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
ClassDB::bind_method(D_METHOD("_set_messages", "messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
@@ -293,31 +306,35 @@ void TranslationServer::init_locale_info() {
}
String TranslationServer::standardize_locale(const String &p_locale) const {
+ return _standardize_locale(p_locale, false);
+}
+
+String TranslationServer::_standardize_locale(const String &p_locale, bool p_add_defaults) const {
// Replaces '-' with '_' for macOS style locales.
String univ_locale = p_locale.replace("-", "_");
// Extract locale elements.
- String lang, script, country, variant;
+ String lang_name, script_name, country_name, variant_name;
Vector<String> locale_elements = univ_locale.get_slice("@", 0).split("_");
- lang = locale_elements[0];
+ lang_name = locale_elements[0];
if (locale_elements.size() >= 2) {
if (locale_elements[1].length() == 4 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_lower_case(locale_elements[1][1]) && is_ascii_lower_case(locale_elements[1][2]) && is_ascii_lower_case(locale_elements[1][3])) {
- script = locale_elements[1];
+ script_name = locale_elements[1];
}
if (locale_elements[1].length() == 2 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_upper_case(locale_elements[1][1])) {
- country = locale_elements[1];
+ country_name = locale_elements[1];
}
}
if (locale_elements.size() >= 3) {
if (locale_elements[2].length() == 2 && is_ascii_upper_case(locale_elements[2][0]) && is_ascii_upper_case(locale_elements[2][1])) {
- country = locale_elements[2];
- } else if (variant_map.has(locale_elements[2].to_lower()) && variant_map[locale_elements[2].to_lower()] == lang) {
- variant = locale_elements[2].to_lower();
+ country_name = locale_elements[2];
+ } else if (variant_map.has(locale_elements[2].to_lower()) && variant_map[locale_elements[2].to_lower()] == lang_name) {
+ variant_name = locale_elements[2].to_lower();
}
}
if (locale_elements.size() >= 4) {
- if (variant_map.has(locale_elements[3].to_lower()) && variant_map[locale_elements[3].to_lower()] == lang) {
- variant = locale_elements[3].to_lower();
+ if (variant_map.has(locale_elements[3].to_lower()) && variant_map[locale_elements[3].to_lower()] == lang_name) {
+ variant_name = locale_elements[3].to_lower();
}
}
@@ -325,74 +342,76 @@ String TranslationServer::standardize_locale(const String &p_locale) const {
Vector<String> script_extra = univ_locale.get_slice("@", 1).split(";");
for (int i = 0; i < script_extra.size(); i++) {
if (script_extra[i].to_lower() == "cyrillic") {
- script = "Cyrl";
+ script_name = "Cyrl";
break;
} else if (script_extra[i].to_lower() == "latin") {
- script = "Latn";
+ script_name = "Latn";
break;
} else if (script_extra[i].to_lower() == "devanagari") {
- script = "Deva";
+ script_name = "Deva";
break;
- } else if (variant_map.has(script_extra[i].to_lower()) && variant_map[script_extra[i].to_lower()] == lang) {
- variant = script_extra[i].to_lower();
+ } else if (variant_map.has(script_extra[i].to_lower()) && variant_map[script_extra[i].to_lower()] == lang_name) {
+ variant_name = script_extra[i].to_lower();
}
}
// Handles known non-ISO language names used e.g. on Windows.
- if (locale_rename_map.has(lang)) {
- lang = locale_rename_map[lang];
+ if (locale_rename_map.has(lang_name)) {
+ lang_name = locale_rename_map[lang_name];
}
// Handle country renames.
- if (country_rename_map.has(country)) {
- country = country_rename_map[country];
+ if (country_rename_map.has(country_name)) {
+ country_name = country_rename_map[country_name];
}
// Remove unsupported script codes.
- if (!script_map.has(script)) {
- script = "";
+ if (!script_map.has(script_name)) {
+ script_name = "";
}
// Add script code base on language and country codes for some ambiguous cases.
- if (script.is_empty()) {
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang) {
- if (country.is_empty() || info.supported_countries.has(country)) {
- script = info.script;
- break;
+ if (p_add_defaults) {
+ if (script_name.is_empty()) {
+ for (int i = 0; i < locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = locale_script_info[i];
+ if (info.name == lang_name) {
+ if (country_name.is_empty() || info.supported_countries.has(country_name)) {
+ script_name = info.script;
+ break;
+ }
}
}
}
- }
- if (!script.is_empty() && country.is_empty()) {
- // Add conntry code based on script for some ambiguous cases.
- for (int i = 0; i < locale_script_info.size(); i++) {
- const LocaleScriptInfo &info = locale_script_info[i];
- if (info.name == lang && info.script == script) {
- country = info.default_country;
- break;
+ if (!script_name.is_empty() && country_name.is_empty()) {
+ // Add conntry code based on script for some ambiguous cases.
+ for (int i = 0; i < locale_script_info.size(); i++) {
+ const LocaleScriptInfo &info = locale_script_info[i];
+ if (info.name == lang_name && info.script == script_name) {
+ country_name = info.default_country;
+ break;
+ }
}
}
}
// Combine results.
- String locale = lang;
- if (!script.is_empty()) {
- locale = locale + "_" + script;
+ String out = lang_name;
+ if (!script_name.is_empty()) {
+ out = out + "_" + script_name;
}
- if (!country.is_empty()) {
- locale = locale + "_" + country;
+ if (!country_name.is_empty()) {
+ out = out + "_" + country_name;
}
- if (!variant.is_empty()) {
- locale = locale + "_" + variant;
+ if (!variant_name.is_empty()) {
+ out = out + "_" + variant_name;
}
- return locale;
+ return out;
}
int TranslationServer::compare_locales(const String &p_locale_a, const String &p_locale_b) const {
- String locale_a = standardize_locale(p_locale_a);
- String locale_b = standardize_locale(p_locale_b);
+ String locale_a = _standardize_locale(p_locale_a, true);
+ String locale_b = _standardize_locale(p_locale_b, true);
if (locale_a == locale_b) {
// Exact match.
@@ -420,31 +439,29 @@ int TranslationServer::compare_locales(const String &p_locale_a, const String &p
}
String TranslationServer::get_locale_name(const String &p_locale) const {
- String locale = standardize_locale(p_locale);
-
- String lang, script, country;
- Vector<String> locale_elements = locale.split("_");
- lang = locale_elements[0];
+ String lang_name, script_name, country_name;
+ Vector<String> locale_elements = standardize_locale(p_locale).split("_");
+ lang_name = locale_elements[0];
if (locale_elements.size() >= 2) {
if (locale_elements[1].length() == 4 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_lower_case(locale_elements[1][1]) && is_ascii_lower_case(locale_elements[1][2]) && is_ascii_lower_case(locale_elements[1][3])) {
- script = locale_elements[1];
+ script_name = locale_elements[1];
}
if (locale_elements[1].length() == 2 && is_ascii_upper_case(locale_elements[1][0]) && is_ascii_upper_case(locale_elements[1][1])) {
- country = locale_elements[1];
+ country_name = locale_elements[1];
}
}
if (locale_elements.size() >= 3) {
if (locale_elements[2].length() == 2 && is_ascii_upper_case(locale_elements[2][0]) && is_ascii_upper_case(locale_elements[2][1])) {
- country = locale_elements[2];
+ country_name = locale_elements[2];
}
}
- String name = language_map[lang];
- if (!script.is_empty()) {
- name = name + " (" + script_map[script] + ")";
+ String name = language_map[lang_name];
+ if (!script_name.is_empty()) {
+ name = name + " (" + script_map[script_name] + ")";
}
- if (!country.is_empty()) {
- name = name + ", " + country_name_map[country];
+ if (!country_name.is_empty()) {
+ name = name + ", " + country_name_map[country_name];
}
return name;
}
@@ -630,12 +647,12 @@ TranslationServer *TranslationServer::singleton = nullptr;
bool TranslationServer::_load_translations(const String &p_from) {
if (ProjectSettings::get_singleton()->has_setting(p_from)) {
- Vector<String> translations = ProjectSettings::get_singleton()->get(p_from);
+ const Vector<String> &translation_names = GLOBAL_GET(p_from);
- int tcount = translations.size();
+ int tcount = translation_names.size();
if (tcount) {
- const String *r = translations.ptr();
+ const String *r = translation_names.ptr();
for (int i = 0; i < tcount; i++) {
Ref<Translation> tr = ResourceLoader::load(r[i]);
@@ -964,7 +981,6 @@ void TranslationServer::_bind_methods() {
}
void TranslationServer::load_translations() {
- String locale = get_locale();
_load_translations("internationalization/locale/translations"); //all
_load_translations("internationalization/locale/translations_" + locale.substr(0, 2));
diff --git a/core/string/translation.h b/core/string/translation.h
index 3f97a8d4fc..5e8344baac 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -64,6 +64,7 @@ public:
virtual void erase_message(const StringName &p_src_text, const StringName &p_context = "");
virtual void get_message_list(List<StringName> *r_messages) const;
virtual int get_message_count() const;
+ virtual Vector<String> get_translated_message_list() const;
Translation() {}
};
@@ -102,6 +103,7 @@ class TranslationServer : public Object {
static TranslationServer *singleton;
bool _load_translations(const String &p_from);
+ String _standardize_locale(const String &p_locale, bool p_add_defaults) const;
StringName _get_message_from_translations(const StringName &p_message, const StringName &p_context, const String &p_locale, bool plural, const String &p_message_plural = "", int p_n = 0) const;
diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp
index fa656b634d..724c1d42bc 100644
--- a/core/string/translation_po.cpp
+++ b/core/string/translation_po.cpp
@@ -103,6 +103,23 @@ void TranslationPO::_set_messages(const Dictionary &p_messages) {
}
}
+Vector<String> TranslationPO::get_translated_message_list() const {
+ Vector<String> msgs;
+ for (const KeyValue<StringName, HashMap<StringName, Vector<StringName>>> &E : translation_map) {
+ if (E.key != StringName()) {
+ continue;
+ }
+
+ for (const KeyValue<StringName, Vector<StringName>> &E2 : E.value) {
+ for (const StringName &E3 : E2.value) {
+ msgs.push_back(E3);
+ }
+ }
+ }
+
+ return msgs;
+}
+
Vector<String> TranslationPO::_get_message_list() const {
// Return all keys in translation_map.
diff --git a/core/string/translation_po.h b/core/string/translation_po.h
index 7d63af2246..c50ea85744 100644
--- a/core/string/translation_po.h
+++ b/core/string/translation_po.h
@@ -70,6 +70,7 @@ protected:
static void _bind_methods();
public:
+ Vector<String> get_translated_message_list() const override;
void get_message_list(List<StringName> *r_messages) const override;
int get_message_count() const override;
void add_message(const StringName &p_src_text, const StringName &p_xlated_text, const StringName &p_context = "") override;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index d8b93998af..8993f9667d 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -1180,9 +1180,14 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p
int len = length();
while (true) {
- int end = find(p_splitter, from);
- if (end < 0) {
- end = len;
+ int end;
+ if (p_splitter.is_empty()) {
+ end = from + 1;
+ } else {
+ end = find(p_splitter, from);
+ if (end < 0) {
+ end = len;
+ }
}
if (p_allow_empty || (end > from)) {
if (p_maxsplit <= 0) {
@@ -1223,7 +1228,15 @@ Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int
break;
}
- int left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+ int left_edge;
+ if (p_splitter.is_empty()) {
+ left_edge = remaining_len - 1;
+ if (left_edge == 0) {
+ left_edge--; // Skip to the < 0 condition.
+ }
+ } else {
+ left_edge = rfind(p_splitter, remaining_len - p_splitter.length());
+ }
if (left_edge < 0) {
// no more splitters, we're done
@@ -1447,15 +1460,25 @@ String String::num(double p_num, int p_decimals) {
fmt[5] = 'f';
fmt[6] = 0;
}
- char buf[256];
+ // if we want to convert a double with as much decimal places as as
+ // DBL_MAX or DBL_MIN then we would theoretically need a buffer of at least
+ // DBL_MAX_10_EXP + 2 for DBL_MAX and DBL_MAX_10_EXP + 4 for DBL_MIN.
+ // BUT those values where still giving me exceptions, so I tested from
+ // DBL_MAX_10_EXP + 10 incrementing one by one and DBL_MAX_10_EXP + 17 (325)
+ // was the first buffer size not to throw an exception
+ char buf[325];
#if defined(__GNUC__) || defined(_MSC_VER)
- snprintf(buf, 256, fmt, p_num);
+ // PLEASE NOTE that, albeit vcrt online reference states that snprintf
+ // should safely truncate the output to the given buffer size, we have
+ // found a case where this is not true, so we should create a buffer
+ // as big as needed
+ snprintf(buf, 325, fmt, p_num);
#else
sprintf(buf, fmt, p_num);
#endif
- buf[255] = 0;
+ buf[324] = 0;
//destroy trailing zeroes
{
bool period = false;
@@ -1567,10 +1590,11 @@ String String::num_real(double p_num, bool p_trailing) {
#else
int decimals = 6;
#endif
- // We want to align the digits to the above sane default, so we only
- // need to subtract log10 for numbers with a positive power of ten.
- if (p_num > 10) {
- decimals -= (int)floor(log10(p_num));
+ // We want to align the digits to the above sane default, so we only need
+ // to subtract log10 for numbers with a positive power of ten magnitude.
+ double abs_num = Math::abs(p_num);
+ if (abs_num > 10) {
+ decimals -= (int)floor(log10(abs_num));
}
return num(p_num, decimals);
}
@@ -2624,10 +2648,11 @@ double String::to_float() const {
uint32_t String::hash(const char *p_cstr) {
uint32_t hashv = 5381;
- uint32_t c;
+ uint32_t c = *p_cstr++;
- while ((c = *p_cstr++)) {
+ while (c) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ c = *p_cstr++;
}
return hashv;
@@ -2653,10 +2678,11 @@ uint32_t String::hash(const wchar_t *p_cstr, int p_len) {
uint32_t String::hash(const wchar_t *p_cstr) {
uint32_t hashv = 5381;
- uint32_t c;
+ uint32_t c = *p_cstr++;
- while ((c = *p_cstr++)) {
+ while (c) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ c = *p_cstr++;
}
return hashv;
@@ -2673,10 +2699,11 @@ uint32_t String::hash(const char32_t *p_cstr, int p_len) {
uint32_t String::hash(const char32_t *p_cstr) {
uint32_t hashv = 5381;
- uint32_t c;
+ uint32_t c = *p_cstr++;
- while ((c = *p_cstr++)) {
+ while (c) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ c = *p_cstr++;
}
return hashv;
@@ -2687,10 +2714,11 @@ uint32_t String::hash() const {
const char32_t *chr = get_data();
uint32_t hashv = 5381;
- uint32_t c;
+ uint32_t c = *chr++;
- while ((c = *chr++)) {
+ while (c) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ c = *chr++;
}
return hashv;
@@ -2701,10 +2729,11 @@ uint64_t String::hash64() const {
const char32_t *chr = get_data();
uint64_t hashv = 5381;
- uint64_t c;
+ uint64_t c = *chr++;
- while ((c = *chr++)) {
+ while (c) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
+ c = *chr++;
}
return hashv;
@@ -2810,7 +2839,7 @@ String String::substr(int p_from, int p_chars) const {
return String(*this);
}
- String s = String();
+ String s;
s.copy_from_unchecked(&get_data()[p_from], p_chars);
return s;
}
@@ -3662,29 +3691,43 @@ bool String::is_network_share_path() const {
String String::simplify_path() const {
String s = *this;
String drive;
- if (s.begins_with("local://")) {
- drive = "local://";
- s = s.substr(8, s.length());
- } else if (s.begins_with("res://")) {
- drive = "res://";
- s = s.substr(6, s.length());
- } else if (s.begins_with("user://")) {
- drive = "user://";
- s = s.substr(7, s.length());
- } else if (is_network_share_path()) {
- drive = s.substr(0, 2);
- s = s.substr(2, s.length() - 2);
- } else if (s.begins_with("/") || s.begins_with("\\")) {
- drive = s.substr(0, 1);
- s = s.substr(1, s.length() - 1);
- } else {
- int p = s.find(":/");
- if (p == -1) {
- p = s.find(":\\");
+
+ // Check if we have a special path (like res://) or a protocol identifier.
+ int p = s.find("://");
+ bool found = false;
+ if (p > 0) {
+ bool only_chars = true;
+ for (int i = 0; i < p; i++) {
+ if (!is_ascii_alphanumeric_char(s[i])) {
+ only_chars = false;
+ break;
+ }
}
- if (p != -1 && p < s.find("/")) {
- drive = s.substr(0, p + 2);
- s = s.substr(p + 2, s.length());
+ if (only_chars) {
+ found = true;
+ drive = s.substr(0, p + 3);
+ s = s.substr(p + 3);
+ }
+ }
+ if (!found) {
+ if (is_network_share_path()) {
+ // Network path, beginning with // or \\.
+ drive = s.substr(0, 2);
+ s = s.substr(2);
+ } else if (s.begins_with("/") || s.begins_with("\\")) {
+ // Absolute path.
+ drive = s.substr(0, 1);
+ s = s.substr(1);
+ } else {
+ // Windows-style drive path, like C:/ or C:\.
+ p = s.find(":/");
+ if (p == -1) {
+ p = s.find(":\\");
+ }
+ if (p != -1 && p < s.find("/")) {
+ drive = s.substr(0, p + 2);
+ s = s.substr(p + 2);
+ }
}
}
@@ -3879,7 +3922,6 @@ String String::c_unescape() const {
escaped = escaped.replace("\\v", "\v");
escaped = escaped.replace("\\'", "\'");
escaped = escaped.replace("\\\"", "\"");
- escaped = escaped.replace("\\?", "\?");
escaped = escaped.replace("\\\\", "\\");
return escaped;
@@ -3896,7 +3938,6 @@ String String::c_escape() const {
escaped = escaped.replace("\t", "\\t");
escaped = escaped.replace("\v", "\\v");
escaped = escaped.replace("\'", "\\'");
- escaped = escaped.replace("\?", "\\?");
escaped = escaped.replace("\"", "\\\"");
return escaped;
@@ -4646,15 +4687,18 @@ String String::sprintf(const Array &values, bool *error) const {
double value = values[value_index];
bool is_negative = (value < 0);
String str = String::num(ABS(value), min_decimals);
+ const bool is_finite = Math::is_finite(value);
// Pad decimals out.
- str = str.pad_decimals(min_decimals);
+ if (is_finite) {
+ str = str.pad_decimals(min_decimals);
+ }
int initial_len = str.length();
// Padding. Leave room for sign later if required.
int pad_chars_count = (is_negative || show_sign) ? min_chars - 1 : min_chars;
- String pad_char = pad_with_zeros ? String("0") : String(" ");
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
str = str.rpad(pad_chars_count, pad_char);
} else {
@@ -4704,14 +4748,19 @@ String String::sprintf(const Array &values, bool *error) const {
String str = "(";
for (int i = 0; i < count; i++) {
double val = vec[i];
+ String number_str = String::num(ABS(val), min_decimals);
+ const bool is_finite = Math::is_finite(val);
+
// Pad decimals out.
- String number_str = String::num(ABS(val), min_decimals).pad_decimals(min_decimals);
+ if (is_finite) {
+ number_str = number_str.pad_decimals(min_decimals);
+ }
int initial_len = number_str.length();
// Padding. Leave room for sign later if required.
int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
- String pad_char = pad_with_zeros ? String("0") : String(" ");
+ String pad_char = (pad_with_zeros && is_finite) ? String("0") : String(" "); // Never pad NaN or inf with zeros
if (left_justified) {
number_str = number_str.rpad(pad_chars_count, pad_char);
} else {
diff --git a/core/string/ustring.h b/core/string/ustring.h
index b8ae3c2392..8af74584f3 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -28,11 +28,11 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-// Note: _GODOT suffix added to avoid conflict with ICU header with the same guard.
-
#ifndef USTRING_GODOT_H
#define USTRING_GODOT_H
+// Note: _GODOT suffix added to header guard to avoid conflict with ICU header.
+
#include "core/string/char_utils.h"
#include "core/templates/cowdata.h"
#include "core/templates/vector.h"
@@ -345,8 +345,8 @@ public:
String get_slice(String p_splitter, int p_slice) const;
String get_slicec(char32_t p_splitter, int p_slice) const;
- Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
- Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> split(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
+ Vector<String> rsplit(const String &p_splitter = "", bool p_allow_empty = true, int p_maxsplit = 0) const;
Vector<String> split_spaces() const;
Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const;
Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const;
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index f98b2308c9..1482e3eef1 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -46,9 +46,7 @@ class CharString;
template <class T, class V>
class VMap;
-#if !defined(NO_THREADS)
SAFE_NUMERIC_TYPE_PUN_GUARANTEES(uint32_t)
-#endif
// Silence a false positive warning (see GH-52119).
#if defined(__GNUC__) && !defined(__clang__)
diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h
index d85cdf7adc..456a7b01ed 100644
--- a/core/templates/hashfuncs.h
+++ b/core/templates/hashfuncs.h
@@ -61,10 +61,11 @@
static _FORCE_INLINE_ uint32_t hash_djb2(const char *p_cstr) {
const unsigned char *chr = (const unsigned char *)p_cstr;
uint32_t hash = 5381;
- uint32_t c;
+ uint32_t c = *chr++;
- while ((c = *chr++)) {
+ while (c) {
hash = ((hash << 5) + hash) ^ c; /* hash * 33 ^ c */
+ c = *chr++;
}
return hash;
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 49690f2373..dc93acc8ab 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -68,7 +68,7 @@ public:
CRASH_COND_MSG(!data, "Out of memory");
}
- if (!std::is_trivially_constructible<T>::value && !force_trivial) {
+ if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
@@ -81,7 +81,7 @@ public:
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
- if (!std::is_trivially_destructible<T>::value && !force_trivial) {
+ if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
@@ -94,7 +94,7 @@ public:
if (count > p_index) {
data[p_index] = data[count];
}
- if (!std::is_trivially_destructible<T>::value && !force_trivial) {
+ if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
@@ -135,7 +135,7 @@ public:
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
- if (!std::is_trivially_destructible<T>::value && !force_trivial) {
+ if constexpr (!std::is_trivially_destructible<T>::value && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
@@ -152,7 +152,7 @@ public:
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
- if (!std::is_trivially_constructible<T>::value && !force_trivial) {
+ if constexpr (!std::is_trivially_constructible<T>::value && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h
index f1ede556e6..2992dd463e 100644
--- a/core/templates/paged_array.h
+++ b/core/templates/paged_array.h
@@ -268,7 +268,7 @@ public:
uint32_t remainder = count & page_size_mask;
T *remainder_page = nullptr;
- uint32_t remainder_page_id;
+ uint32_t remainder_page_id = 0;
if (remainder > 0) {
uint32_t last_page = _get_pages_in_use() - 1;
diff --git a/core/templates/pooled_list.h b/core/templates/pooled_list.h
index f13156b292..2b67da87ba 100644
--- a/core/templates/pooled_list.h
+++ b/core/templates/pooled_list.h
@@ -28,7 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#pragma once
+#ifndef POOLED_LIST_H
+#define POOLED_LIST_H
// Simple template to provide a pool with O(1) allocate and free.
// The freelist could alternatively be a linked list placed within the unused elements
@@ -111,7 +112,7 @@ public:
list.resize(r_id + 1);
static_assert((!zero_on_first_request) || (__is_pod(T)), "zero_on_first_request requires trivial type");
- if (zero_on_first_request && __is_pod(T)) {
+ if constexpr (zero_on_first_request && __is_pod(T)) {
list[r_id] = {};
}
@@ -206,3 +207,5 @@ private:
LocalVector<U, U> _active_map;
LocalVector<U, U> _active_list;
};
+
+#endif // POOLED_LIST_H
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index 320faebe98..a83ffa575f 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -335,15 +335,8 @@ public:
~RID_Alloc() {
if (alloc_count) {
- if (description) {
- print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + description + "' were leaked at exit.");
- } else {
-#ifdef NO_SAFE_CAST
- print_error("ERROR: " + itos(alloc_count) + " RID allocations of type 'unknown' were leaked at exit.");
-#else
- print_error("ERROR: " + itos(alloc_count) + " RID allocations of type '" + typeid(T).name() + "' were leaked at exit.");
-#endif
- }
+ print_error(vformat("ERROR: %d RID allocations of type '%s' were leaked at exit.",
+ alloc_count, description ? description : typeid(T).name()));
for (size_t i = 0; i < max_alloc; i++) {
uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk];
diff --git a/core/templates/safe_list.h b/core/templates/safe_list.h
index e850f3bd5e..95e8ca1a14 100644
--- a/core/templates/safe_list.h
+++ b/core/templates/safe_list.h
@@ -33,11 +33,9 @@
#include "core/os/memory.h"
#include "core/typedefs.h"
-#include <functional>
-
-#if !defined(NO_THREADS)
#include <atomic>
+#include <functional>
#include <type_traits>
// Design goals for these classes:
@@ -239,159 +237,4 @@ public:
}
};
-#else // NO_THREADS
-
-// Effectively the same structure without the atomics. It's probably possible to simplify it but the semantics shouldn't differ greatly.
-template <class T, class A = DefaultAllocator>
-class SafeList {
- struct SafeListNode {
- SafeListNode *next = nullptr;
-
- // If the node is logically deleted, this pointer will typically point to the previous list item in time that was also logically deleted.
- SafeListNode *graveyard_next = nullptr;
-
- std::function<void(T)> deletion_fn = [](T t) { return; };
-
- T val;
- };
-
- SafeListNode *head = nullptr;
- SafeListNode *graveyard_head = nullptr;
-
- unsigned int active_iterator_count = 0;
-
-public:
- class Iterator {
- friend class SafeList;
-
- SafeListNode *cursor = nullptr;
- SafeList *list = nullptr;
-
- public:
- Iterator(SafeListNode *p_cursor, SafeList *p_list) :
- cursor(p_cursor), list(p_list) {
- list->active_iterator_count++;
- }
-
- ~Iterator() {
- list->active_iterator_count--;
- }
-
- T &operator*() {
- return cursor->val;
- }
-
- Iterator &operator++() {
- cursor = cursor->next;
- return *this;
- }
-
- // These two operators are mostly useful for comparisons to nullptr.
- bool operator==(const void *p_other) const {
- return cursor == p_other;
- }
-
- bool operator!=(const void *p_other) const {
- return cursor != p_other;
- }
-
- // These two allow easy range-based for loops.
- bool operator==(const Iterator &p_other) const {
- return cursor == p_other.cursor;
- }
-
- bool operator!=(const Iterator &p_other) const {
- return cursor != p_other.cursor;
- }
- };
-
-public:
- // Calling this will cause an allocation.
- void insert(T p_value) {
- SafeListNode *new_node = memnew_allocator(SafeListNode, A);
- new_node->val = p_value;
- new_node->next = head;
- head = new_node;
- }
-
- Iterator find(T p_value) {
- for (Iterator it = begin(); it != end(); ++it) {
- if (*it == p_value) {
- return it;
- }
- }
- return end();
- }
-
- void erase(T p_value, std::function<void(T)> p_deletion_fn) {
- erase(find(p_value), p_deletion_fn);
- }
-
- void erase(T p_value) {
- erase(find(p_value), [](T t) { return; });
- }
-
- void erase(Iterator p_iterator, std::function<void(T)> p_deletion_fn) {
- p_iterator.cursor->deletion_fn = p_deletion_fn;
- erase(p_iterator);
- }
-
- void erase(Iterator p_iterator) {
- Iterator prev = begin();
- for (; prev != end(); ++prev) {
- if (prev.cursor && prev.cursor->next == p_iterator.cursor) {
- break;
- }
- }
- if (prev == end()) {
- // Not in the list, nothing to do.
- return;
- }
- // First, remove the node from the list.
- prev.cursor->next = p_iterator.cursor->next;
-
- // Then queue it for deletion by putting it in the node graveyard. Don't touch `next` because an iterator might still be pointing at this node.
- p_iterator.cursor->graveyard_next = graveyard_head;
- graveyard_head = p_iterator.cursor;
- }
-
- Iterator begin() {
- return Iterator(head, this);
- }
-
- Iterator end() {
- return Iterator(nullptr, this);
- }
-
- // Calling this will cause zero to many deallocations.
- bool maybe_cleanup() {
- SafeListNode *cursor = graveyard_head;
- if (active_iterator_count != 0) {
- // It's not safe to clean up with an active iterator, because that iterator could be pointing to an element that we want to delete.
- return false;
- }
- graveyard_head = nullptr;
- // Our graveyard list is now unreachable by any active iterators, detached from the main graveyard head and ready for deletion.
- while (cursor) {
- SafeListNode *tmp = cursor;
- cursor = cursor->next;
- tmp->deletion_fn(tmp->val);
- memdelete_allocator<SafeListNode, A>(tmp);
- }
- return true;
- }
-
- ~SafeList() {
-#ifdef DEBUG_ENABLED
- if (!maybe_cleanup()) {
- ERR_PRINT("There are still iterators around when destructing a SafeList. Memory will be leaked. This is a bug.");
- }
-#else
- maybe_cleanup();
-#endif
- }
-};
-
-#endif
-
#endif // SAFE_LIST_H
diff --git a/core/templates/safe_refcount.h b/core/templates/safe_refcount.h
index 1f6551762e..c4ffe5ca02 100644
--- a/core/templates/safe_refcount.h
+++ b/core/templates/safe_refcount.h
@@ -33,8 +33,6 @@
#include "core/typedefs.h"
-#if !defined(NO_THREADS)
-
#include <atomic>
#include <type_traits>
@@ -191,141 +189,4 @@ public:
}
};
-#else
-
-template <class T>
-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;
- }
- return value;
- }
-
- _ALWAYS_INLINE_ T conditional_increment() {
- if (value == 0) {
- return 0;
- } else {
- return ++value;
- }
- }
-
- _ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
- value(p_value) {
- }
-};
-
-class SafeFlag {
-protected:
- bool flag;
-
-public:
- _ALWAYS_INLINE_ bool is_set() const {
- return flag;
- }
-
- _ALWAYS_INLINE_ void set() {
- flag = true;
- }
-
- _ALWAYS_INLINE_ void clear() {
- flag = false;
- }
-
- _ALWAYS_INLINE_ void set_to(bool p_value) {
- flag = p_value;
- }
-
- _ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
- flag(p_value) {}
-};
-
-class SafeRefCount {
- uint32_t count = 0;
-
-public:
- _ALWAYS_INLINE_ bool ref() { // true on success
- if (count != 0) {
- ++count;
- return true;
- } else {
- return false;
- }
- }
-
- _ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
- if (count != 0) {
- return ++count;
- } else {
- return 0;
- }
- }
-
- _ALWAYS_INLINE_ bool unref() { // true if must be disposed of
- return --count == 0;
- }
-
- _ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
- return --count;
- }
-
- _ALWAYS_INLINE_ uint32_t get() const {
- return count;
- }
-
- _ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
- count = p_value;
- }
-};
-
-#endif
-
#endif // SAFE_REFCOUNT_H
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index c1bdd6a6bc..c6bbd43dc4 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -31,6 +31,7 @@
#include "array.h"
#include "container_type_validate.h"
+#include "core/math/math_funcs.h"
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/templates/hashfuncs.h"
@@ -299,6 +300,11 @@ Variant Array::back() const {
return operator[](_p->array.size() - 1);
}
+Variant Array::pick_random() const {
+ ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array.");
+ return operator[](Math::rand() % _p->array.size());
+}
+
int Array::find(const Variant &p_value, int p_from) const {
ERR_FAIL_COND_V(!_p->typed.validate(p_value, "find"), -1);
return _p->array.find(p_value, p_from);
@@ -402,6 +408,7 @@ Array Array::recursive_duplicate(bool p_deep, int recursion_count) const {
Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
Array result;
+ result._p->typed = _p->typed;
ERR_FAIL_COND_V_MSG(p_step == 0, result, "Slice step cannot be zero.");
@@ -433,6 +440,7 @@ Array Array::slice(int p_begin, int p_end, int p_step, bool p_deep) const {
Array Array::filter(const Callable &p_callable) const {
Array new_arr;
new_arr.resize(size());
+ new_arr._p->typed = _p->typed;
int accepted_count = 0;
const Variant *argptrs[1];
diff --git a/core/variant/array.h b/core/variant/array.h
index c007376734..ee265a9ffd 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -47,7 +47,6 @@ class Array {
void _unref() const;
protected:
- Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
bool _assign(const Array &p_array);
public:
@@ -80,6 +79,7 @@ public:
Variant front() const;
Variant back() const;
+ Variant pick_random() const;
void sort();
void sort_custom(const Callable &p_callable);
@@ -131,6 +131,7 @@ public:
void set_read_only(bool p_enable);
bool is_read_only() const;
+ Array(const Array &p_base, uint32_t p_type, const StringName &p_class_name, const Variant &p_script);
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h
index f0c3b1ce38..696b27f9f2 100644
--- a/core/variant/binder_common.h
+++ b/core/variant/binder_common.h
@@ -138,7 +138,7 @@ VARIANT_ENUM_CAST(Vector3::Axis);
VARIANT_ENUM_CAST(Vector3i::Axis);
VARIANT_ENUM_CAST(Vector4::Axis);
VARIANT_ENUM_CAST(Vector4i::Axis);
-VARIANT_ENUM_CAST(Basis::EulerOrder);
+VARIANT_ENUM_CAST(EulerOrder);
VARIANT_ENUM_CAST(Projection::Planes);
VARIANT_ENUM_CAST(Error);
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 28efb43fc5..79532d9aca 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -63,6 +63,21 @@ void Callable::callp(const Variant **p_arguments, int p_argcount, Variant &r_ret
}
}
+Variant Callable::callv(const Array &p_arguments) const {
+ int argcount = p_arguments.size();
+ const Variant **argptrs = nullptr;
+ if (argcount) {
+ argptrs = (const Variant **)alloca(sizeof(Variant *) * argcount);
+ for (int i = 0; i < argcount; i++) {
+ argptrs[i] = &p_arguments[i];
+ }
+ }
+ CallError ce;
+ Variant ret;
+ callp(argptrs, argcount, ret, ce);
+ return ret;
+}
+
Error Callable::rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
if (is_null()) {
r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
@@ -387,33 +402,33 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
}
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
- Object *object = get_object();
- ERR_FAIL_COND_V(!object, ERR_UNCONFIGURED);
+ Object *obj = get_object();
+ ERR_FAIL_COND_V(!obj, ERR_UNCONFIGURED);
- return object->connect(name, p_callable, p_flags);
+ return obj->connect(name, p_callable, p_flags);
}
void Signal::disconnect(const Callable &p_callable) {
- Object *object = get_object();
- ERR_FAIL_COND(!object);
- object->disconnect(name, p_callable);
+ Object *obj = get_object();
+ ERR_FAIL_COND(!obj);
+ obj->disconnect(name, p_callable);
}
bool Signal::is_connected(const Callable &p_callable) const {
- Object *object = get_object();
- ERR_FAIL_COND_V(!object, false);
+ Object *obj = get_object();
+ ERR_FAIL_COND_V(!obj, false);
- return object->is_connected(name, p_callable);
+ return obj->is_connected(name, p_callable);
}
Array Signal::get_connections() const {
- Object *object = get_object();
- if (!object) {
+ Object *obj = get_object();
+ if (!obj) {
return Array();
}
List<Object::Connection> connections;
- object->get_signal_connection_list(name, &connections);
+ obj->get_signal_connection_list(name, &connections);
Array arr;
for (const Object::Connection &E : connections) {
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 1f1c983eb3..32770bd663 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -71,6 +71,17 @@ public:
void callp(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferredp(const Variant **p_arguments, int p_argcount) const;
+ Variant callv(const Array &p_arguments) const;
+
+ template <typename... VarArgs>
+ void call_deferred(VarArgs... p_args) const {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., 0 }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return call_deferredp(sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
Error rpcp(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index 6171c8c88f..427a337aab 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -79,9 +79,12 @@ struct ContainerTypeValidate {
return true;
}
- ERR_FAIL_COND_V_MSG(type != p_variant.get_type(), false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
if (type != p_variant.get_type()) {
- return false;
+ if (p_variant.get_type() == Variant::NIL && type == Variant::OBJECT) {
+ return true;
+ }
+
+ ERR_FAIL_V_MSG(false, "Attempted to " + String(p_operation) + " a variable of type '" + Variant::get_type_name(p_variant.get_type()) + "' into a " + where + " of type '" + Variant::get_type_name(type) + "'.");
}
if (type != Variant::OBJECT) {
@@ -90,7 +93,7 @@ struct ContainerTypeValidate {
#ifdef DEBUG_ENABLED
ObjectID object_id = p_variant;
if (object_id == ObjectID()) {
- return true; //fine its null;
+ return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
@@ -101,7 +104,7 @@ struct ContainerTypeValidate {
}
#endif
if (class_name == StringName()) {
- return true; //all good, no class type requested
+ return true; // All good, no class type requested.
}
StringName obj_class = object->get_class_name();
@@ -110,12 +113,12 @@ struct ContainerTypeValidate {
}
if (script.is_null()) {
- return true; //all good
+ return true; // All good, no script requested.
}
Ref<Script> other_script = object->get_script();
- //check base script..
+ // Check base script..
ERR_FAIL_COND_V_MSG(other_script.is_null(), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
ERR_FAIL_COND_V_MSG(!other_script->inherits_script(script), false, "Attempted to " + String(p_operation) + " an object into a " + String(where) + ", that does not inherit from '" + String(script->get_class_name()) + "'.");
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index 7372c60754..e355053296 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -276,7 +276,7 @@ inline String enum_qualified_name_to_class_info_name(const String &p_qualified_n
template <typename T>
inline StringName __constant_get_enum_name(T param, const String &p_constant) {
- if (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
+ if constexpr (GetTypeInfo<T>::VARIANT_TYPE == Variant::NIL) {
ERR_PRINT("Missing VARIANT_ENUM_CAST for constant's enum: " + p_constant);
}
return GetTypeInfo<T>::get_class_info().class_name;
@@ -284,14 +284,14 @@ inline StringName __constant_get_enum_name(T param, const String &p_constant) {
template <class T>
class BitField {
- uint32_t value = 0;
+ int64_t value = 0;
public:
_FORCE_INLINE_ void set_flag(T p_flag) { value |= p_flag; }
_FORCE_INLINE_ bool has_flag(T p_flag) const { return value & p_flag; }
_FORCE_INLINE_ void clear_flag(T p_flag) { return value &= ~p_flag; }
- _FORCE_INLINE_ BitField(uint32_t p_value) { value = p_value; }
- _FORCE_INLINE_ operator uint32_t() const { return value; }
+ _FORCE_INLINE_ BitField(int64_t p_value) { value = p_value; }
+ _FORCE_INLINE_ operator int64_t() const { return value; }
_FORCE_INLINE_ operator Variant() const { return value; }
};
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index f24ffeb1a9..c1166a0a14 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -47,146 +47,126 @@ String Variant::get_type_name(Variant::Type p_type) {
switch (p_type) {
case NIL: {
return "Nil";
- } break;
+ }
- // atomic types
+ // Atomic types.
case BOOL: {
return "bool";
- } break;
+ }
case INT: {
return "int";
-
- } break;
+ }
case FLOAT: {
return "float";
-
- } break;
+ }
case STRING: {
return "String";
- } break;
+ }
- // math types
+ // Math types.
case VECTOR2: {
return "Vector2";
- } break;
+ }
case VECTOR2I: {
return "Vector2i";
- } break;
+ }
case RECT2: {
return "Rect2";
- } break;
+ }
case RECT2I: {
return "Rect2i";
- } break;
+ }
case TRANSFORM2D: {
return "Transform2D";
- } break;
+ }
case VECTOR3: {
return "Vector3";
- } break;
+ }
case VECTOR3I: {
return "Vector3i";
- } break;
+ }
case VECTOR4: {
return "Vector4";
- } break;
+ }
case VECTOR4I: {
return "Vector4i";
- } break;
+ }
case PLANE: {
return "Plane";
-
- } break;
+ }
case AABB: {
return "AABB";
- } break;
+ }
case QUATERNION: {
return "Quaternion";
-
- } break;
+ }
case BASIS: {
return "Basis";
-
- } break;
+ }
case TRANSFORM3D: {
return "Transform3D";
-
- } break;
+ }
case PROJECTION: {
return "Projection";
+ }
- } break;
-
- // misc types
+ // Miscellaneous types.
case COLOR: {
return "Color";
-
- } break;
+ }
case RID: {
return "RID";
- } break;
+ }
case OBJECT: {
return "Object";
- } break;
+ }
case CALLABLE: {
return "Callable";
- } break;
+ }
case SIGNAL: {
return "Signal";
- } break;
+ }
case STRING_NAME: {
return "StringName";
-
- } break;
+ }
case NODE_PATH: {
return "NodePath";
-
- } break;
+ }
case DICTIONARY: {
return "Dictionary";
-
- } break;
+ }
case ARRAY: {
return "Array";
+ }
- } break;
-
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
return "PackedByteArray";
-
- } break;
+ }
case PACKED_INT32_ARRAY: {
return "PackedInt32Array";
-
- } break;
+ }
case PACKED_INT64_ARRAY: {
return "PackedInt64Array";
-
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return "PackedFloat32Array";
-
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return "PackedFloat64Array";
-
- } break;
+ }
case PACKED_STRING_ARRAY: {
return "PackedStringArray";
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return "PackedVector2Array";
-
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return "PackedVector3Array";
-
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return "PackedColorArray";
-
- } break;
+ }
default: {
}
}
@@ -880,157 +860,126 @@ bool Variant::is_zero() const {
switch (type) {
case NIL: {
return true;
- } break;
+ }
- // atomic types
+ // Atomic types.
case BOOL: {
return !(_data._bool);
- } break;
+ }
case INT: {
return _data._int == 0;
-
- } break;
+ }
case FLOAT: {
return _data._float == 0;
-
- } break;
+ }
case STRING: {
return *reinterpret_cast<const String *>(_data._mem) == String();
+ }
- } break;
-
- // math types
+ // Math types.
case VECTOR2: {
return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2();
-
- } break;
+ }
case VECTOR2I: {
return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i();
-
- } break;
+ }
case RECT2: {
return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2();
-
- } break;
+ }
case RECT2I: {
return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i();
-
- } break;
+ }
case TRANSFORM2D: {
return *_data._transform2d == Transform2D();
-
- } break;
+ }
case VECTOR3: {
return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3();
-
- } break;
+ }
case VECTOR3I: {
return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i();
-
- } break;
+ }
case VECTOR4: {
return *reinterpret_cast<const Vector4 *>(_data._mem) == Vector4();
-
- } break;
+ }
case VECTOR4I: {
return *reinterpret_cast<const Vector4i *>(_data._mem) == Vector4i();
-
- } break;
+ }
case PLANE: {
return *reinterpret_cast<const Plane *>(_data._mem) == Plane();
-
- } break;
+ }
case AABB: {
return *_data._aabb == ::AABB();
- } break;
+ }
case QUATERNION: {
return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion();
-
- } break;
+ }
case BASIS: {
return *_data._basis == Basis();
-
- } break;
+ }
case TRANSFORM3D: {
return *_data._transform3d == Transform3D();
-
- } break;
+ }
case PROJECTION: {
return *_data._projection == Projection();
+ }
- } break;
-
- // misc types
+ // Miscellaneous types.
case COLOR: {
return *reinterpret_cast<const Color *>(_data._mem) == Color();
-
- } break;
+ }
case RID: {
return *reinterpret_cast<const ::RID *>(_data._mem) == ::RID();
- } break;
+ }
case OBJECT: {
return _get_obj().obj == nullptr;
- } break;
+ }
case CALLABLE: {
return reinterpret_cast<const Callable *>(_data._mem)->is_null();
- } break;
+ }
case SIGNAL: {
return reinterpret_cast<const Signal *>(_data._mem)->is_null();
- } break;
+ }
case STRING_NAME: {
return *reinterpret_cast<const StringName *>(_data._mem) != StringName();
-
- } break;
+ }
case NODE_PATH: {
return reinterpret_cast<const NodePath *>(_data._mem)->is_empty();
-
- } break;
+ }
case DICTIONARY: {
return reinterpret_cast<const Dictionary *>(_data._mem)->is_empty();
-
- } break;
+ }
case ARRAY: {
return reinterpret_cast<const Array *>(_data._mem)->is_empty();
+ }
- } break;
-
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
return PackedArrayRef<uint8_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_INT32_ARRAY: {
return PackedArrayRef<int32_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_INT64_ARRAY: {
return PackedArrayRef<int64_t>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return PackedArrayRef<float>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return PackedArrayRef<double>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_STRING_ARRAY: {
return PackedArrayRef<String>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return PackedArrayRef<Vector2>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return PackedArrayRef<Vector3>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return PackedArrayRef<Color>::get_array(_data.packed_array).size() == 0;
-
- } break;
+ }
default: {
}
}
@@ -1042,67 +991,54 @@ bool Variant::is_one() const {
switch (type) {
case NIL: {
return true;
- } break;
+ }
- // atomic types
case BOOL: {
return _data._bool;
- } break;
+ }
case INT: {
return _data._int == 1;
-
- } break;
+ }
case FLOAT: {
return _data._float == 1;
+ }
- } break;
case VECTOR2: {
return *reinterpret_cast<const Vector2 *>(_data._mem) == Vector2(1, 1);
-
- } break;
+ }
case VECTOR2I: {
return *reinterpret_cast<const Vector2i *>(_data._mem) == Vector2i(1, 1);
-
- } break;
+ }
case RECT2: {
return *reinterpret_cast<const Rect2 *>(_data._mem) == Rect2(1, 1, 1, 1);
-
- } break;
+ }
case RECT2I: {
return *reinterpret_cast<const Rect2i *>(_data._mem) == Rect2i(1, 1, 1, 1);
-
- } break;
+ }
case VECTOR3: {
return *reinterpret_cast<const Vector3 *>(_data._mem) == Vector3(1, 1, 1);
-
- } break;
+ }
case VECTOR3I: {
return *reinterpret_cast<const Vector3i *>(_data._mem) == Vector3i(1, 1, 1);
-
- } break;
+ }
case VECTOR4: {
return *reinterpret_cast<const Vector4 *>(_data._mem) == Vector4(1, 1, 1, 1);
-
- } break;
+ }
case VECTOR4I: {
return *reinterpret_cast<const Vector4i *>(_data._mem) == Vector4i(1, 1, 1, 1);
-
- } break;
+ }
case PLANE: {
return *reinterpret_cast<const Plane *>(_data._mem) == Plane(1, 1, 1, 1);
+ }
- } break;
case COLOR: {
return *reinterpret_cast<const Color *>(_data._mem) == Color(1, 1, 1, 1);
-
- } break;
+ }
default: {
return !is_zero();
}
}
-
- return false;
}
bool Variant::is_null() const {
@@ -1135,10 +1071,10 @@ void Variant::reference(const Variant &p_variant) {
switch (p_variant.type) {
case NIL: {
- // none
+ // None.
} break;
- // atomic types
+ // Atomic types.
case BOOL: {
_data._bool = p_variant._data._bool;
} break;
@@ -1152,7 +1088,7 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, String(*reinterpret_cast<const String *>(p_variant._data._mem)));
} break;
- // math types
+ // Math types.
case VECTOR2: {
memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem)));
} break;
@@ -1204,10 +1140,9 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._projection, Projection(*p_variant._data._projection));
} break;
- // misc types
+ // Miscellaneous types.
case COLOR: {
memnew_placement(_data._mem, Color(*reinterpret_cast<const Color *>(p_variant._data._mem)));
-
} break;
case RID: {
memnew_placement(_data._mem, ::RID(*reinterpret_cast<const ::RID *>(p_variant._data._mem)));
@@ -1226,7 +1161,6 @@ void Variant::reference(const Variant &p_variant) {
_get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj);
_get_obj().id = p_variant._get_obj().id;
-
} break;
case CALLABLE: {
memnew_placement(_data._mem, Callable(*reinterpret_cast<const Callable *>(p_variant._data._mem)));
@@ -1236,84 +1170,71 @@ void Variant::reference(const Variant &p_variant) {
} break;
case STRING_NAME: {
memnew_placement(_data._mem, StringName(*reinterpret_cast<const StringName *>(p_variant._data._mem)));
-
} break;
case NODE_PATH: {
memnew_placement(_data._mem, NodePath(*reinterpret_cast<const NodePath *>(p_variant._data._mem)));
-
} break;
case DICTIONARY: {
memnew_placement(_data._mem, Dictionary(*reinterpret_cast<const Dictionary *>(p_variant._data._mem)));
-
} break;
case ARRAY: {
memnew_placement(_data._mem, Array(*reinterpret_cast<const Array *>(p_variant._data._mem)));
-
} break;
- // arrays
+ // Arrays.
case PACKED_BYTE_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<uint8_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<uint8_t>::create();
}
-
} break;
case PACKED_INT32_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<int32_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<int32_t>::create();
}
-
} break;
case PACKED_INT64_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<int64_t> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<int64_t>::create();
}
-
} break;
case PACKED_FLOAT32_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<float> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<float>::create();
}
-
} break;
case PACKED_FLOAT64_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<double> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<double>::create();
}
-
} break;
case PACKED_STRING_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<String> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<String>::create();
}
-
} break;
case PACKED_VECTOR2_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Vector2> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Vector2>::create();
}
-
} break;
case PACKED_VECTOR3_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Vector3> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Vector3>::create();
}
-
} break;
case PACKED_COLOR_ARRAY: {
_data.packed_array = static_cast<PackedArrayRef<Color> *>(p_variant._data.packed_array)->reference();
if (!_data.packed_array) {
_data.packed_array = PackedArrayRef<Color>::create();
}
-
} break;
default: {
}
@@ -1333,6 +1254,7 @@ void Variant::zero() {
case FLOAT:
this->_data._float = 0;
break;
+
case VECTOR2:
*reinterpret_cast<Vector2 *>(this->_data._mem) = Vector2();
break;
@@ -1363,9 +1285,11 @@ void Variant::zero() {
case QUATERNION:
*reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion();
break;
+
case COLOR:
*reinterpret_cast<Color *>(this->_data._mem) = Color();
break;
+
default:
this->clear();
break;
@@ -1377,15 +1301,8 @@ void Variant::_clear_internal() {
case STRING: {
reinterpret_cast<String *>(_data._mem)->~String();
} break;
- /*
- // no point, they don't allocate memory
- VECTOR3,
- PLANE,
- QUATERNION,
- COLOR,
- VECTOR2,
- RECT2
- */
+
+ // Math types.
case TRANSFORM2D: {
if (_data._transform2d) {
_data._transform2d->~Transform2D();
@@ -1421,7 +1338,8 @@ void Variant::_clear_internal() {
_data._projection = nullptr;
}
} break;
- // misc types
+
+ // Miscellaneous types.
case STRING_NAME: {
reinterpret_cast<StringName *>(_data._mem)->~StringName();
} break;
@@ -1430,7 +1348,7 @@ void Variant::_clear_internal() {
} break;
case OBJECT: {
if (_get_obj().id.is_ref_counted()) {
- //we are safe that there is a reference here
+ // We are safe that there is a reference here.
RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj);
if (ref_counted->unreference()) {
memdelete(ref_counted);
@@ -1440,8 +1358,8 @@ void Variant::_clear_internal() {
_get_obj().id = ObjectID();
} break;
case RID: {
- // not much need probably
- // Can't seem to use destructor + scoping operator, so hack.
+ // Not much need probably.
+ // HACK: Can't seem to use destructor + scoping operator, so hack.
typedef ::RID RID_Class;
reinterpret_cast<RID_Class *>(_data._mem)->~RID_Class();
} break;
@@ -1457,7 +1375,8 @@ void Variant::_clear_internal() {
case ARRAY: {
reinterpret_cast<Array *>(_data._mem)->~Array();
} break;
- // arrays
+
+ // Arrays.
case PACKED_BYTE_ARRAY: {
PackedArrayRefBase::destroy(_data.packed_array);
} break;
@@ -1486,7 +1405,9 @@ void Variant::_clear_internal() {
PackedArrayRefBase::destroy(_data.packed_array);
} break;
default: {
- } /* not needed */
+ // Not needed, there is no point. The following do not allocate memory:
+ // VECTOR2, VECTOR3, RECT2, PLANE, QUATERNION, COLOR.
+ }
}
}
@@ -1835,11 +1756,13 @@ String Variant::stringify(int recursion_count) const {
case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
if (recursion_count > MAX_RECURSION) {
- ERR_PRINT("Max recursion reached");
- return "{...}";
+ ERR_PRINT("Maximum dictionary recursion reached!");
+ return "{ ... }";
}
- String str("{");
+ // Add leading and trailing space to Dictionary printing. This distinguishes it
+ // from array printing on fonts that have similar-looking {} and [] characters.
+ String str("{ ");
List<Variant> keys;
d.get_key_list(&keys);
@@ -1858,49 +1781,48 @@ String Variant::stringify(int recursion_count) const {
if (i > 0) {
str += ", ";
}
- str += pairs[i].key + ":" + pairs[i].value;
+ str += pairs[i].key + ": " + pairs[i].value;
}
- str += "}";
+ str += " }";
return str;
- } break;
+ }
case PACKED_VECTOR2_ARRAY: {
return stringify_vector(operator Vector<Vector2>(), recursion_count);
- } break;
+ }
case PACKED_VECTOR3_ARRAY: {
return stringify_vector(operator Vector<Vector3>(), recursion_count);
- } break;
+ }
case PACKED_COLOR_ARRAY: {
return stringify_vector(operator Vector<Color>(), recursion_count);
- } break;
+ }
case PACKED_STRING_ARRAY: {
return stringify_vector(operator Vector<String>(), recursion_count);
- } break;
+ }
case PACKED_BYTE_ARRAY: {
return stringify_vector(operator Vector<uint8_t>(), recursion_count);
- } break;
+ }
case PACKED_INT32_ARRAY: {
return stringify_vector(operator Vector<int32_t>(), recursion_count);
- } break;
+ }
case PACKED_INT64_ARRAY: {
return stringify_vector(operator Vector<int64_t>(), recursion_count);
- } break;
+ }
case PACKED_FLOAT32_ARRAY: {
return stringify_vector(operator Vector<float>(), recursion_count);
- } break;
+ }
case PACKED_FLOAT64_ARRAY: {
return stringify_vector(operator Vector<double>(), recursion_count);
- } break;
+ }
case ARRAY: {
Array arr = operator Array();
if (recursion_count > MAX_RECURSION) {
- ERR_PRINT("Max recursion reached");
+ ERR_PRINT("Maximum array recursion reached!");
return "[...]";
}
return stringify_vector(arr, recursion_count);
-
- } break;
+ }
case OBJECT: {
if (_get_obj().obj) {
if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) {
@@ -1911,31 +1833,27 @@ String Variant::stringify(int recursion_count) const {
} else {
return "<Object#null>";
}
-
- } break;
+ }
case CALLABLE: {
const Callable &c = *reinterpret_cast<const Callable *>(_data._mem);
return c;
- } break;
+ }
case SIGNAL: {
const Signal &s = *reinterpret_cast<const Signal *>(_data._mem);
return s;
- } break;
+ }
case RID: {
const ::RID &s = *reinterpret_cast<const ::RID *>(_data._mem);
return "RID(" + itos(s.get_id()) + ")";
- } break;
+ }
default: {
return "<" + get_type_name(type) + ">";
}
}
-
- return "";
}
String Variant::to_json_string() const {
- JSON json;
- return json.stringify(*this);
+ return JSON::stringify(*this);
}
Variant::operator Vector2() const {
@@ -3121,22 +3039,22 @@ uint32_t Variant::recursive_hash(int recursion_count) const {
case PROJECTION: {
uint32_t h = HASH_MURMUR3_SEED;
const Projection &t = *_data._projection;
- h = hash_murmur3_one_real(t.matrix[0].x, h);
- h = hash_murmur3_one_real(t.matrix[0].y, h);
- h = hash_murmur3_one_real(t.matrix[0].z, h);
- h = hash_murmur3_one_real(t.matrix[0].w, h);
- h = hash_murmur3_one_real(t.matrix[1].x, h);
- h = hash_murmur3_one_real(t.matrix[1].y, h);
- h = hash_murmur3_one_real(t.matrix[1].z, h);
- h = hash_murmur3_one_real(t.matrix[1].w, h);
- h = hash_murmur3_one_real(t.matrix[2].x, h);
- h = hash_murmur3_one_real(t.matrix[2].y, h);
- h = hash_murmur3_one_real(t.matrix[2].z, h);
- h = hash_murmur3_one_real(t.matrix[2].w, h);
- h = hash_murmur3_one_real(t.matrix[3].x, h);
- h = hash_murmur3_one_real(t.matrix[3].y, h);
- h = hash_murmur3_one_real(t.matrix[3].z, h);
- h = hash_murmur3_one_real(t.matrix[3].w, h);
+ h = hash_murmur3_one_real(t.columns[0].x, h);
+ h = hash_murmur3_one_real(t.columns[0].y, h);
+ h = hash_murmur3_one_real(t.columns[0].z, h);
+ h = hash_murmur3_one_real(t.columns[0].w, h);
+ h = hash_murmur3_one_real(t.columns[1].x, h);
+ h = hash_murmur3_one_real(t.columns[1].y, h);
+ h = hash_murmur3_one_real(t.columns[1].z, h);
+ h = hash_murmur3_one_real(t.columns[1].w, h);
+ h = hash_murmur3_one_real(t.columns[2].x, h);
+ h = hash_murmur3_one_real(t.columns[2].y, h);
+ h = hash_murmur3_one_real(t.columns[2].z, h);
+ h = hash_murmur3_one_real(t.columns[2].w, h);
+ h = hash_murmur3_one_real(t.columns[3].x, h);
+ h = hash_murmur3_one_real(t.columns[3].y, h);
+ h = hash_murmur3_one_real(t.columns[3].z, h);
+ h = hash_murmur3_one_real(t.columns[3].w, h);
return hash_fmix32(h);
} break;
// misc types
@@ -3507,7 +3425,7 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
const Projection *r = p_variant._data._projection;
for (int i = 0; i < 4; i++) {
- if (!(hash_compare_vector4(l->matrix[i], r->matrix[i]))) {
+ if (!(hash_compare_vector4(l->columns[i], r->columns[i]))) {
return false;
}
}
@@ -3571,8 +3489,6 @@ bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const
evaluate(OP_EQUAL, *this, p_variant, r, v);
return r;
}
-
- return false;
}
bool Variant::is_ref_counted() const {
@@ -3693,16 +3609,16 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
if (ce.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = ce.argument;
if (p_argptrs) {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(ce.expected));
} else {
- err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected)) + ".";
+ err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(Variant::Type(ce.expected));
}
} else if (ce.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount);
} else if (ce.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + ".";
+ err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount);
} else if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- err_text = "Method not found.";
+ err_text = "Method not found";
} else if (ce.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
err_text = "Instance is null";
} else if (ce.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index b0738e7d44..c5be609184 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -490,6 +490,7 @@ public:
}
// Only enum classes that need to be bound need this to be defined.
+ VARIANT_ENUM_CLASS_CONSTRUCTOR(EulerOrder)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyAxis)
VARIANT_ENUM_CLASS_CONSTRUCTOR(JoyButton)
VARIANT_ENUM_CLASS_CONSTRUCTOR(Key)
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index f09885b325..a231a956bf 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1509,8 +1509,8 @@ static void _register_variant_builtin_methods() {
bind_method(String, to_camel_case, sarray(), varray());
bind_method(String, to_pascal_case, sarray(), varray());
bind_method(String, to_snake_case, sarray(), varray());
- bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
- bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray(true, 0));
+ bind_method(String, split, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
+ bind_method(String, rsplit, sarray("delimiter", "allow_empty", "maxsplit"), varray("", true, 0));
bind_method(String, split_floats, sarray("delimiter", "allow_empty"), varray(true));
bind_method(String, join, sarray("parts"), varray());
@@ -1606,6 +1606,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, is_normalized, sarray(), varray());
bind_method(Vector2, is_equal_approx, sarray("to"), varray());
bind_method(Vector2, is_zero_approx, sarray(), varray());
+ bind_method(Vector2, is_finite, sarray(), varray());
bind_method(Vector2, posmod, sarray("mod"), varray());
bind_method(Vector2, posmodv, sarray("modv"), varray());
bind_method(Vector2, project, sarray("b"), varray());
@@ -1653,6 +1654,7 @@ static void _register_variant_builtin_methods() {
bind_method(Rect2, has_area, sarray(), varray());
bind_method(Rect2, has_point, sarray("point"), varray());
bind_method(Rect2, is_equal_approx, sarray("rect"), varray());
+ bind_method(Rect2, is_finite, sarray(), varray());
bind_method(Rect2, intersects, sarray("b", "include_borders"), varray(false));
bind_method(Rect2, encloses, sarray("b"), varray());
bind_method(Rect2, intersection, sarray("b"), varray());
@@ -1695,6 +1697,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, is_zero_approx, sarray(), varray());
+ bind_method(Vector3, is_finite, sarray(), varray());
bind_method(Vector3, inverse, sarray(), varray());
bind_method(Vector3, clamp, sarray("min", "max"), varray());
bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1759,6 +1762,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
bind_method(Vector4, is_zero_approx, sarray(), varray());
+ bind_method(Vector4, is_finite, sarray(), varray());
/* Vector4i */
@@ -1775,6 +1779,7 @@ static void _register_variant_builtin_methods() {
bind_method(Plane, normalized, sarray(), varray());
bind_method(Plane, center, sarray(), varray());
bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
+ bind_method(Plane, is_finite, sarray(), varray());
bind_method(Plane, is_point_over, sarray("point"), varray());
bind_method(Plane, distance_to, sarray("point"), varray());
bind_method(Plane, has_point, sarray("point", "tolerance"), varray(CMP_EPSILON));
@@ -1790,6 +1795,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, normalized, sarray(), varray());
bind_method(Quaternion, is_normalized, sarray(), varray());
bind_method(Quaternion, is_equal_approx, sarray("to"), varray());
+ bind_method(Quaternion, is_finite, sarray(), varray());
bind_method(Quaternion, inverse, sarray(), varray());
bind_method(Quaternion, log, sarray(), varray());
bind_method(Quaternion, exp, sarray(), varray());
@@ -1799,7 +1805,8 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, slerpni, sarray("to", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
- bind_method(Quaternion, get_euler, sarray(), varray());
+ bind_method(Quaternion, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
+ bind_static_method(Quaternion, from_euler, sarray("euler"), varray());
bind_method(Quaternion, get_axis, sarray(), varray());
bind_method(Quaternion, get_angle, sarray(), varray());
@@ -1829,10 +1836,6 @@ static void _register_variant_builtin_methods() {
bind_static_method(Color, hex64, sarray("hex"), varray());
bind_static_method(Color, html, sarray("rgba"), varray());
bind_static_method(Color, html_is_valid, sarray("color"), varray());
- bind_static_method(Color, find_named_color, sarray("name"), varray());
- bind_static_method(Color, get_named_color_count, sarray(), varray());
- bind_static_method(Color, get_named_color_name, sarray("idx"), varray());
- bind_static_method(Color, get_named_color, sarray("idx"), varray());
bind_static_method(Color, from_string, sarray("str", "default"), varray());
bind_static_method(Color, from_hsv, sarray("h", "s", "v", "alpha"), varray(1.0));
bind_static_method(Color, from_ok_hsl, sarray("h", "s", "l", "alpha"), varray(1.0));
@@ -1859,6 +1862,7 @@ static void _register_variant_builtin_methods() {
/* Callable */
+ bind_method(Callable, callv, sarray("arguments"), varray());
bind_method(Callable, is_null, sarray(), varray());
bind_method(Callable, is_custom, sarray(), varray());
bind_method(Callable, is_standard, sarray(), varray());
@@ -1908,6 +1912,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform2D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform2D, is_finite, sarray(), varray());
bind_method(Transform2D, set_rotation, sarray("rotation"), varray());
bind_method(Transform2D, set_scale, sarray("scale"), varray());
bind_method(Transform2D, set_skew, sarray("skew"), varray());
@@ -1922,16 +1927,17 @@ static void _register_variant_builtin_methods() {
bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "angle"), varray());
bind_method(Basis, scaled, sarray("scale"), varray());
bind_method(Basis, get_scale, sarray(), varray());
- bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ));
+ bind_method(Basis, get_euler, sarray("order"), varray((int64_t)EulerOrder::YXZ));
bind_method(Basis, tdotx, sarray("with"), varray());
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
+ bind_method(Basis, is_finite, sarray(), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_static_method(Basis, from_scale, sarray("scale"), varray());
- bind_static_method(Basis, from_euler, sarray("euler", "order"), varray(Basis::EULER_ORDER_YXZ));
+ bind_static_method(Basis, from_euler, sarray("euler", "order"), varray((int64_t)EulerOrder::YXZ));
/* AABB */
@@ -1942,6 +1948,7 @@ static void _register_variant_builtin_methods() {
bind_method(AABB, has_surface, sarray(), varray());
bind_method(AABB, has_point, sarray("point"), varray());
bind_method(AABB, is_equal_approx, sarray("aabb"), varray());
+ bind_method(AABB, is_finite, sarray(), varray());
bind_method(AABB, intersects, sarray("with"), varray());
bind_method(AABB, encloses, sarray("with"), varray());
bind_method(AABB, intersects_plane, sarray("plane"), varray());
@@ -1974,6 +1981,7 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray());
bind_method(Transform3D, is_equal_approx, sarray("xform"), varray());
+ bind_method(Transform3D, is_finite, sarray(), varray());
/* Projection */
@@ -2042,6 +2050,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
bind_method(Array, back, sarray(), varray());
+ bind_method(Array, pick_random, sarray(), varray());
bind_method(Array, find, sarray("what", "from"), varray(0));
bind_method(Array, rfind, sarray("what", "from"), varray(-1));
bind_method(Array, find_last, sarray("value"), varray());
@@ -2065,6 +2074,14 @@ static void _register_variant_builtin_methods() {
bind_method(Array, all, sarray("method"), varray());
bind_method(Array, max, sarray(), varray());
bind_method(Array, min, sarray(), varray());
+ bind_method(Array, typed_assign, sarray("array"), varray());
+ bind_method(Array, set_typed, sarray("type", "class_name", "script"), varray());
+ bind_method(Array, is_typed, sarray(), varray());
+ bind_method(Array, get_typed_builtin, sarray(), varray());
+ bind_method(Array, get_typed_class_name, sarray(), varray());
+ bind_method(Array, get_typed_script, sarray(), varray());
+ bind_method(Array, set_read_only, sarray("enable"), varray());
+ bind_method(Array, is_read_only, sarray(), varray());
/* Byte Array */
bind_method(PackedByteArray, size, sarray(), varray());
@@ -2417,25 +2434,11 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1));
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY);
- _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX);
-
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY);
- _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX);
-
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D());
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0));
_VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0));
- Transform3D identity_transform = Transform3D();
+ Transform3D identity_transform;
Transform3D flip_x_transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0);
Transform3D flip_y_transform = Transform3D(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0);
Transform3D flip_z_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0);
@@ -2444,7 +2447,7 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Y", flip_y_transform);
_VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Z", flip_z_transform);
- Basis identity_basis = Basis();
+ Basis identity_basis;
Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1);
Basis flip_y_basis = Basis(1, 0, 0, 0, -1, 0, 0, 0, 1);
Basis flip_z_basis = Basis(1, 0, 0, 0, 1, 0, 0, 0, -1);
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 78ae2cefaa..624a6f5e06 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -143,7 +143,6 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle"));
add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to"));
add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w"));
- add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler_yxz"));
add_constructor<VariantConstructNoArgs<::AABB>>(sarray());
add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from"));
@@ -202,6 +201,7 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Array>>(sarray());
add_constructor<VariantConstructor<Array, Array>>(sarray("from"));
+ add_constructor<VariantConstructorTypedArray>(sarray("base", "type", "class_name", "script"));
add_constructor<VariantConstructorToArray<PackedByteArray>>(sarray("from"));
add_constructor<VariantConstructorToArray<PackedInt32Array>>(sarray("from"));
add_constructor<VariantConstructorToArray<PackedInt64Array>>(sarray("from"));
diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h
index d77feb5970..f52cc43914 100644
--- a/core/variant/variant_construct.h
+++ b/core/variant/variant_construct.h
@@ -394,6 +394,82 @@ public:
}
};
+class VariantConstructorTypedArray {
+public:
+ static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) {
+ if (p_args[0]->get_type() != Variant::ARRAY) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::ARRAY;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::INT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::INT;
+ return;
+ }
+
+ if (p_args[2]->get_type() != Variant::STRING_NAME) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 2;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ const uint32_t type = p_args[1]->operator uint32_t();
+ const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
+ r_ret = Array(base_arr, type, class_name, *p_args[3]);
+ }
+
+ static inline void validated_construct(Variant *r_ret, const Variant **p_args) {
+ const Array &base_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]);
+ const uint32_t type = p_args[1]->operator uint32_t();
+ const StringName &class_name = *VariantGetInternalPtr<StringName>::get_ptr(p_args[2]);
+ *r_ret = Array(base_arr, type, class_name, *p_args[3]);
+ }
+
+ static void ptr_construct(void *base, const void **p_args) {
+ const Array &base_arr = PtrToArg<Array>::convert(p_args[0]);
+ const uint32_t type = PtrToArg<uint32_t>::convert(p_args[1]);
+ const StringName &class_name = PtrToArg<StringName>::convert(p_args[2]);
+ const Variant &script = PtrToArg<Variant>::convert(p_args[3]);
+ Array dst_arr = Array(base_arr, type, class_name, script);
+
+ PtrConstruct<Array>::construct(dst_arr, base);
+ }
+
+ static int get_argument_count() {
+ return 4;
+ }
+
+ static Variant::Type get_argument_type(int p_arg) {
+ switch (p_arg) {
+ case 0: {
+ return Variant::ARRAY;
+ } break;
+ case 1: {
+ return Variant::INT;
+ } break;
+ case 2: {
+ return Variant::STRING_NAME;
+ } break;
+ case 3: {
+ return Variant::NIL;
+ } break;
+ default: {
+ return Variant::NIL;
+ } break;
+ }
+ }
+
+ static Variant::Type get_base_type() {
+ return Variant::ARRAY;
+ }
+};
+
template <class T>
class VariantConstructorToArray {
public:
diff --git a/core/variant/variant_destruct.cpp b/core/variant/variant_destruct.cpp
index ab8303f3ae..5117c33e2b 100644
--- a/core/variant/variant_destruct.cpp
+++ b/core/variant/variant_destruct.cpp
@@ -41,13 +41,8 @@ static void add_destructor() {
void Variant::_register_variant_destructors() {
add_destructor<VariantDestruct<String>>();
- add_destructor<VariantDestruct<Transform2D>>();
- add_destructor<VariantDestruct<::AABB>>();
- add_destructor<VariantDestruct<Basis>>();
- add_destructor<VariantDestruct<Transform3D>>();
add_destructor<VariantDestruct<StringName>>();
add_destructor<VariantDestruct<NodePath>>();
- add_destructor<VariantDestruct<::RID>>();
add_destructor<VariantDestruct<Callable>>();
add_destructor<VariantDestruct<Signal>>();
add_destructor<VariantDestruct<Dictionary>>();
diff --git a/core/variant/variant_destruct.h b/core/variant/variant_destruct.h
index 5e3478635d..2730110c0f 100644
--- a/core/variant/variant_destruct.h
+++ b/core/variant/variant_destruct.h
@@ -50,13 +50,8 @@ struct VariantDestruct {};
}
MAKE_PTRDESTRUCT(String);
-MAKE_PTRDESTRUCT(Transform2D);
-MAKE_PTRDESTRUCT(AABB);
-MAKE_PTRDESTRUCT(Basis);
-MAKE_PTRDESTRUCT(Transform3D);
MAKE_PTRDESTRUCT(StringName);
MAKE_PTRDESTRUCT(NodePath);
-MAKE_PTRDESTRUCT(RID);
MAKE_PTRDESTRUCT(Callable);
MAKE_PTRDESTRUCT(Signal);
MAKE_PTRDESTRUCT(Dictionary);
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 874a183d29..94e7296a99 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -824,9 +824,9 @@ VARIANT_ACCESSOR_NUMBER(Vector4i::Axis)
VARIANT_ACCESSOR_NUMBER(Projection::Planes)
template <>
-struct VariantInternalAccessor<Basis::EulerOrder> {
- static _FORCE_INLINE_ Basis::EulerOrder get(const Variant *v) { return Basis::EulerOrder(*VariantInternal::get_int(v)); }
- static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = p_value; }
+struct VariantInternalAccessor<EulerOrder> {
+ static _FORCE_INLINE_ EulerOrder get(const Variant *v) { return EulerOrder(*VariantInternal::get_int(v)); }
+ static _FORCE_INLINE_ void set(Variant *v, EulerOrder p_value) { *VariantInternal::get_int(v) = (int64_t)p_value; }
};
template <>
@@ -1047,7 +1047,7 @@ struct VariantInternalAccessor<PackedColorArray> {
template <>
struct VariantInternalAccessor<Object *> {
static _FORCE_INLINE_ Object *get(const Variant *v) { return const_cast<Object *>(*VariantInternal::get_object(v)); }
- static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { *VariantInternal::get_object(v) = const_cast<Object *>(p_value); }
+ static _FORCE_INLINE_ void set(Variant *v, const Object *p_value) { VariantInternal::object_assign(v, p_value); }
};
template <>
@@ -1532,27 +1532,4 @@ struct VariantTypeConstructor {
}
};
-template <>
-struct VariantTypeConstructor<Object *> {
- _FORCE_INLINE_ static void variant_from_type(void *p_variant, void *p_value) {
- Variant *variant = reinterpret_cast<Variant *>(p_variant);
- VariantInitializer<Object *>::init(variant);
- Object *object = *(reinterpret_cast<Object **>(p_value));
- if (object) {
- if (object->is_ref_counted()) {
- if (!VariantInternal::initialize_ref(object)) {
- return;
- }
- }
- VariantInternalAccessor<Object *>::set(variant, object);
- VariantInternalAccessor<ObjectID>::set(variant, object->get_instance_id());
- }
- }
-
- _FORCE_INLINE_ static void type_from_variant(void *p_value, void *p_variant) {
- Object **value = reinterpret_cast<Object **>(p_value);
- *value = VariantInternalAccessor<Object *>::get(reinterpret_cast<Variant *>(p_variant));
- }
-};
-
#endif // VARIANT_INTERNAL_H
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 6cca7955ae..25bc241e9b 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -240,8 +240,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAdd<double, double, int64_t>>(Variant::OP_ADD, Variant::FLOAT, Variant::INT);
register_op<OperatorEvaluatorAdd<double, double, double>>(Variant::OP_ADD, Variant::FLOAT, Variant::FLOAT);
register_op<OperatorEvaluatorAdd<String, String, String>>(Variant::OP_ADD, Variant::STRING, Variant::STRING);
- register_op<OperatorEvaluatorAdd<String, char32_t, String>>(Variant::OP_ADD, Variant::INT, Variant::STRING);
- register_op<OperatorEvaluatorAdd<String, String, char32_t>>(Variant::OP_ADD, Variant::STRING, Variant::INT);
register_op<OperatorEvaluatorAdd<Vector2, Vector2, Vector2>>(Variant::OP_ADD, Variant::VECTOR2, Variant::VECTOR2);
register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I);
register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3);
@@ -384,10 +382,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorDivNZ<Vector2, Vector2i, double>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::FLOAT);
register_op<OperatorEvaluatorDivNZ<Vector2i, Vector2i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2I, Variant::INT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, Vector2>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::VECTOR2);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, double>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::FLOAT);
- register_op<OperatorEvaluatorDiv<Vector2, Vector2, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR2, Variant::INT);
-
register_op<OperatorEvaluatorDiv<Vector3, Vector3, Vector3>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::VECTOR3);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, double>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::FLOAT);
register_op<OperatorEvaluatorDiv<Vector3, Vector3, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3, Variant::INT);
@@ -498,8 +492,6 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorBitXor<int64_t, int64_t, int64_t>>(Variant::OP_BIT_XOR, Variant::INT, Variant::INT);
register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
- register_op<OperatorEvaluatorBitNeg<int64_t, int64_t>>(Variant::OP_BIT_NEGATE, Variant::INT, Variant::NIL);
-
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_EQUAL, Variant::NIL, Variant::NIL>>(Variant::OP_EQUAL, Variant::NIL, Variant::NIL);
register_op<OperatorEvaluatorEqual<bool, bool>>(Variant::OP_EQUAL, Variant::BOOL, Variant::BOOL);
register_op<OperatorEvaluatorEqual<int64_t, int64_t>>(Variant::OP_EQUAL, Variant::INT, Variant::INT);
@@ -567,6 +559,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::AABB, Variant::NIL>>(Variant::OP_EQUAL, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::BASIS, Variant::NIL>>(Variant::OP_EQUAL, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::NIL>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::PROJECTION, Variant::NIL>>(Variant::OP_EQUAL, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::COLOR, Variant::NIL>>(Variant::OP_EQUAL, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::STRING_NAME, Variant::NIL>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NIL>>(Variant::OP_EQUAL, Variant::NODE_PATH, Variant::NIL);
@@ -603,6 +596,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::AABB>>(Variant::OP_EQUAL, Variant::NIL, Variant::AABB);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::BASIS>>(Variant::OP_EQUAL, Variant::NIL, Variant::BASIS);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::TRANSFORM3D>>(Variant::OP_EQUAL, Variant::NIL, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::PROJECTION>>(Variant::OP_EQUAL, Variant::NIL, Variant::PROJECTION);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::COLOR>>(Variant::OP_EQUAL, Variant::NIL, Variant::COLOR);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::STRING_NAME>>(Variant::OP_EQUAL, Variant::NIL, Variant::STRING_NAME);
register_op<OperatorEvaluatorAlwaysFalse<Variant::OP_EQUAL, Variant::NIL, Variant::NODE_PATH>>(Variant::OP_EQUAL, Variant::NIL, Variant::NODE_PATH);
@@ -688,6 +682,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::AABB, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::NIL);
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::PROJECTION, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::NIL);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NIL>>(Variant::OP_NOT_EQUAL, Variant::NODE_PATH, Variant::NIL);
@@ -724,6 +719,7 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::AABB>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::AABB);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::BASIS>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::BASIS);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::TRANSFORM3D>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::PROJECTION>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::PROJECTION);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::COLOR>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::COLOR);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::STRING_NAME>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::STRING_NAME);
register_op<OperatorEvaluatorAlwaysTrue<Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NODE_PATH>>(Variant::OP_NOT_EQUAL, Variant::NIL, Variant::NODE_PATH);
diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp
index 8151ff2102..d2e4d752a4 100644
--- a/core/variant/variant_parser.cpp
+++ b/core/variant/variant_parser.cpp
@@ -1651,7 +1651,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
if (i != 0 || j != 0) {
s += ", ";
}
- s += rtos_fix(t.matrix[i][j]);
+ s += rtos_fix(t.columns[i][j]);
}
}
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index ff67b187ef..188103ee5e 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -826,7 +826,7 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4)
INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .columns, 3)
INDEXED_SETGET_STRUCT_BULTIN_FUNC(Basis, Vector3, set_column, get_column, 3)
-INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Projection, Vector4, .matrix, 4)
+INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Projection, Vector4, .columns, 4)
INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedByteArray, int64_t, uint8_t)
INDEXED_SETGET_STRUCT_TYPED_NUMERIC(PackedInt32Array, int64_t, int32_t)
diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h
index 570277dc7a..d151a85a6e 100644
--- a/core/variant/variant_setget.h
+++ b/core/variant/variant_setget.h
@@ -325,10 +325,10 @@ SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_column, get_column, 2)
SETGET_STRUCT(Transform3D, Basis, basis)
SETGET_STRUCT(Transform3D, Vector3, origin)
-SETGET_STRUCT_CUSTOM(Projection, Vector4, x, matrix[0])
-SETGET_STRUCT_CUSTOM(Projection, Vector4, y, matrix[1])
-SETGET_STRUCT_CUSTOM(Projection, Vector4, z, matrix[2])
-SETGET_STRUCT_CUSTOM(Projection, Vector4, w, matrix[3])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, x, columns[0])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, y, columns[1])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, z, columns[2])
+SETGET_STRUCT_CUSTOM(Projection, Vector4, w, columns[3])
SETGET_NUMBER_STRUCT(Color, double, r)
SETGET_NUMBER_STRUCT(Color, double, g)
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index 7ff64c88f0..3843c32bcc 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -128,8 +128,8 @@ struct VariantUtilityFunctions {
return Math::floor(x);
}
- static inline int floori(double x) {
- return int(x);
+ static inline int64_t floori(double x) {
+ return int64_t(Math::floor(x));
}
static inline Variant ceil(Variant x, Callable::CallError &r_error) {
@@ -161,8 +161,8 @@ struct VariantUtilityFunctions {
return Math::ceil(x);
}
- static inline int ceili(double x) {
- return int(Math::ceil(x));
+ static inline int64_t ceili(double x) {
+ return int64_t(Math::ceil(x));
}
static inline Variant round(Variant x, Callable::CallError &r_error) {
@@ -194,8 +194,8 @@ struct VariantUtilityFunctions {
return Math::round(x);
}
- static inline int roundi(double x) {
- return int(Math::round(x));
+ static inline int64_t roundi(double x) {
+ return int64_t(Math::round(x));
}
static inline Variant abs(const Variant &x, Callable::CallError &r_error) {
@@ -310,6 +310,10 @@ struct VariantUtilityFunctions {
return Math::is_zero_approx(x);
}
+ static inline bool is_finite(double x) {
+ return Math::is_finite(x);
+ }
+
static inline double ease(float x, float curve) {
return Math::ease(x, curve);
}
@@ -1420,6 +1424,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(is_equal_approx, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(is_zero_approx, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(is_finite, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ease, sarray("x", "curve"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);