diff options
Diffstat (limited to 'core')
162 files changed, 5175 insertions, 2110 deletions
diff --git a/core/SCsub b/core/SCsub index bdf8544840..e3ba46be02 100644 --- a/core/SCsub +++ b/core/SCsub @@ -59,6 +59,7 @@ thirdparty_misc_sources = [ "pcg.cpp", "polypartition.cpp", "clipper.cpp", + "smolv.cpp", ] thirdparty_misc_sources = [thirdparty_misc_dir + file for file in thirdparty_misc_sources] env_thirdparty.add_source_files(thirdparty_obj, thirdparty_misc_sources) diff --git a/core/config/engine.cpp b/core/config/engine.cpp index 2360d66438..99ec1aeb5b 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -31,6 +31,7 @@ #include "engine.h" #include "core/authors.gen.h" +#include "core/config/project_settings.h" #include "core/donors.gen.h" #include "core/license.gen.h" #include "core/version.h" @@ -210,6 +211,13 @@ void Engine::get_singletons(List<Singleton> *p_singletons) { } } +void Engine::set_shader_cache_path(const String &p_path) { + shader_cache_path = p_path; +} +String Engine::get_shader_cache_path() const { + return shader_cache_path; +} + Engine *Engine::singleton = nullptr; Engine *Engine::get_singleton() { @@ -224,9 +232,9 @@ Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) : name(p_name), ptr(p_ptr) { #ifdef DEBUG_ENABLED - Reference *ref = Object::cast_to<Reference>(p_ptr); - if (ref && !ref->is_referenced()) { - WARN_PRINT("You must use Ref<> to ensure the lifetime of a Reference object intended to be used as a singleton."); + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); + if (rc && !rc->is_referenced()) { + WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton."); } #endif } diff --git a/core/config/engine.h b/core/config/engine.h index a9080e3dfd..276da1c7ea 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -72,6 +72,8 @@ private: static Engine *singleton; + String shader_cache_path; + public: static Engine *get_singleton(); @@ -121,6 +123,9 @@ public: Dictionary get_license_info() const; String get_license_text() const; + void set_shader_cache_path(const String &p_path); + String get_shader_cache_path() const; + bool is_abort_on_gpu_errors_enabled() const; bool is_validation_layers_enabled() const; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 0d699cdacb..590c3ff50e 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -33,11 +33,11 @@ #include "core/core_bind.h" #include "core/core_string_names.h" #include "core/input/input_map.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_network.h" #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" @@ -62,7 +62,7 @@ String ProjectSettings::localize_path(const String &p_path) const { } if (p_path.begins_with("res://") || p_path.begins_with("user://") || - (p_path.is_abs_path() && !p_path.begins_with(resource_path))) { + (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) { return p_path.simplify_path(); } @@ -1102,7 +1102,7 @@ ProjectSettings::ProjectSettings() { if (Engine::get_singleton()->has_singleton("GodotSharp")) { extensions.push_back("cs"); } - extensions.push_back("shader"); + extensions.push_back("gdshader"); GLOBAL_DEF("editor/run/main_run_args", ""); @@ -1114,7 +1114,8 @@ ProjectSettings::ProjectSettings() { _add_builtin_input_map(); - custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::STRING, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "landscape,portrait,reverse_landscape,reverse_portrait,sensor_landscape,sensor_portrait,sensor"); + // Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum. + custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"); custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); GLOBAL_DEF("physics/2d/run_on_thread", false); GLOBAL_DEF("physics/3d/run_on_thread", false); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 84d8d0d4d3..60759cd71c 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -42,28 +42,6 @@ #include "core/os/keyboard.h" #include "core/os/os.h" -/** - * Time constants borrowed from loc_time.h - */ -#define EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */ -#define SECS_DAY (24L * 60L * 60L) -#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) -#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) -#define SECOND_KEY "second" -#define MINUTE_KEY "minute" -#define HOUR_KEY "hour" -#define DAY_KEY "day" -#define MONTH_KEY "month" -#define YEAR_KEY "year" -#define WEEKDAY_KEY "weekday" -#define DST_KEY "dst" - -/// Table of number of days in each month (for regular year and leap year) -static const unsigned int MONTH_DAYS_TABLE[2][12] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - ////// _ResourceLoader ////// _ResourceLoader *_ResourceLoader::singleton = nullptr; @@ -322,198 +300,6 @@ uint64_t _OS::get_static_memory_peak_usage() const { return OS::get_singleton()->get_static_memory_peak_usage(); } -/** - * Get current datetime with consideration for utc and - * dst - */ -Dictionary _OS::get_datetime(bool utc) const { - Dictionary dated = get_date(utc); - Dictionary timed = get_time(utc); - - List<Variant> keys; - timed.get_key_list(&keys); - - for (int i = 0; i < keys.size(); i++) { - dated[keys[i]] = timed[keys[i]]; - } - - return dated; -} - -Dictionary _OS::get_date(bool utc) const { - OS::Date date = OS::get_singleton()->get_date(utc); - Dictionary dated; - dated[YEAR_KEY] = date.year; - dated[MONTH_KEY] = date.month; - dated[DAY_KEY] = date.day; - dated[WEEKDAY_KEY] = date.weekday; - dated[DST_KEY] = date.dst; - return dated; -} - -Dictionary _OS::get_time(bool utc) const { - OS::Time time = OS::get_singleton()->get_time(utc); - Dictionary timed; - timed[HOUR_KEY] = time.hour; - timed[MINUTE_KEY] = time.min; - timed[SECOND_KEY] = time.sec; - return timed; -} - -/** - * Get an epoch time value from a dictionary of time values - * @p datetime must be populated with the following keys: - * day, hour, minute, month, second, year. (dst is ignored). - * - * You can pass the output from - * get_datetime_from_unix_time directly into this function - * - * @param datetime dictionary of date and time values to convert - * - * @return epoch calculated - */ -int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { - // if datetime is an empty Dictionary throws an error - ERR_FAIL_COND_V_MSG(datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); - - // Bunch of conversion constants - static const unsigned int SECONDS_PER_MINUTE = 60; - static const unsigned int MINUTES_PER_HOUR = 60; - static const unsigned int HOURS_PER_DAY = 24; - static const unsigned int SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE; - static const unsigned int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; - - // Get all time values from the dictionary, set to zero if it doesn't exist. - // Risk incorrect calculation over throwing errors - unsigned int second = ((datetime.has(SECOND_KEY)) ? static_cast<unsigned int>(datetime[SECOND_KEY]) : 0); - unsigned int minute = ((datetime.has(MINUTE_KEY)) ? static_cast<unsigned int>(datetime[MINUTE_KEY]) : 0); - unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast<unsigned int>(datetime[HOUR_KEY]) : 0); - unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 1); - unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) : 1); - unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast<unsigned int>(datetime[YEAR_KEY]) : 0); - - /// How many days come before each month (0-12) - static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - - ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + "."); - - ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); - - ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); - - ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + "."); - - // Do this check after month is tested as valid - ERR_FAIL_COND_V_MSG(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 0, "Invalid day value of '" + itos(day) + "' which is larger than '" + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + "' or 0."); - // Calculate all the seconds from months past in this year - uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; - - int64_t SECONDS_FROM_YEARS_PAST = 0; - if (year >= EPOCH_YR) { - for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { - SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; - } - } else { - for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) { - SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY; - } - } - - int64_t epoch = - second + - minute * SECONDS_PER_MINUTE + - hour * SECONDS_PER_HOUR + - // Subtract 1 from day, since the current day isn't over yet - // and we cannot count all 24 hours. - (day - 1) * SECONDS_PER_DAY + - SECONDS_FROM_MONTHS_PAST_THIS_YEAR + - SECONDS_FROM_YEARS_PAST; - return epoch; -} - -/** - * Get a dictionary of time values when given epoch time - * - * Dictionary Time values will be a union if values from #get_time - * and #get_date dictionaries (with the exception of dst = - * day light standard time, as it cannot be determined from epoch) - * - * @param unix_time_val epoch time to convert - * - * @return dictionary of date and time values - */ -Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { - OS::Date date; - OS::Time time; - - long dayclock, dayno; - int year = EPOCH_YR; - - if (unix_time_val >= 0) { - dayno = unix_time_val / SECS_DAY; - dayclock = unix_time_val % SECS_DAY; - /* day 0 was a thursday */ - date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); - while (dayno >= YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - } else { - dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; - dayclock = unix_time_val - dayno * SECS_DAY; - date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7); - do { - year--; - dayno += YEARSIZE(year); - } while (dayno < 0); - } - - time.sec = dayclock % 60; - time.min = (dayclock % 3600) / 60; - time.hour = dayclock / 3600; - date.year = year; - - size_t imonth = 0; - - while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) { - dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]; - imonth++; - } - - /// Add 1 to month to make sure months are indexed starting at 1 - date.month = static_cast<OS::Month>(imonth + 1); - - date.day = dayno + 1; - - Dictionary timed; - timed[HOUR_KEY] = time.hour; - timed[MINUTE_KEY] = time.min; - timed[SECOND_KEY] = time.sec; - timed[YEAR_KEY] = date.year; - timed[MONTH_KEY] = date.month; - timed[DAY_KEY] = date.day; - timed[WEEKDAY_KEY] = date.weekday; - - return timed; -} - -Dictionary _OS::get_time_zone_info() const { - OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info(); - Dictionary infod; - infod["bias"] = info.bias; - infod["name"] = info.name; - return infod; -} - -double _OS::get_unix_time() const { - return OS::get_singleton()->get_unix_time(); -} - /** This method uses a signed argument for better error reporting as it's used from the scripting API. */ void _OS::delay_usec(int p_usec) const { ERR_FAIL_COND_MSG( @@ -530,14 +316,6 @@ void _OS::delay_msec(int p_msec) const { OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000); } -uint32_t _OS::get_ticks_msec() const { - return OS::get_singleton()->get_ticks_msec(); -} - -uint64_t _OS::get_ticks_usec() const { - return OS::get_singleton()->get_ticks_usec(); -} - bool _OS::can_use_threads() const { return OS::get_singleton()->can_use_threads(); } @@ -644,6 +422,10 @@ String _OS::get_user_data_dir() const { return OS::get_singleton()->get_user_data_dir(); } +String _OS::get_external_data_dir() const { + return OS::get_singleton()->get_external_data_dir(); +} + bool _OS::is_debug_build() const { #ifdef DEBUG_ENABLED return true; @@ -713,18 +495,8 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name); ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args); - ClassDB::bind_method(D_METHOD("get_datetime", "utc"), &_OS::get_datetime, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_date", "utc"), &_OS::get_date, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_time", "utc"), &_OS::get_time, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_time_zone_info"), &_OS::get_time_zone_info); - ClassDB::bind_method(D_METHOD("get_unix_time"), &_OS::get_unix_time); - ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time); - ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime); - ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec); ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec); - ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec); - ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec); ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale); ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name); @@ -744,6 +516,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &_OS::get_static_memory_peak_usage); ClassDB::bind_method(D_METHOD("get_user_data_dir"), &_OS::get_user_data_dir); + ClassDB::bind_method(D_METHOD("get_external_data_dir"), &_OS::get_external_data_dir); ClassDB::bind_method(D_METHOD("get_system_dir", "dir"), &_OS::get_system_dir); ClassDB::bind_method(D_METHOD("get_unique_id"), &_OS::get_unique_id); @@ -1226,7 +999,7 @@ Error _File::open(const String &p_path, ModeFlags p_mode_flags) { Error err; f = FileAccess::open(p_path, p_mode_flags, &err); if (f) { - f->set_endian_swap(eswap); + f->set_big_endian(big_endian); } return err; } @@ -1259,6 +1032,7 @@ String _File::get_path_absolute() const { void _File::seek(int64_t p_position) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND_MSG(p_position < 0, "Seek position must be a positive integer."); f->seek(p_position); } @@ -1267,14 +1041,14 @@ void _File::seek_end(int64_t p_position) { f->seek_end(p_position); } -int64_t _File::get_position() const { +uint64_t _File::get_position() const { ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); return f->get_position(); } -int64_t _File::get_len() const { +uint64_t _File::get_length() const { ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); - return f->get_len(); + return f->get_length(); } bool _File::eof_reached() const { @@ -1317,7 +1091,7 @@ real_t _File::get_real() const { return f->get_real(); } -Vector<uint8_t> _File::get_buffer(int p_length) const { +Vector<uint8_t> _File::get_buffer(int64_t p_length) const { Vector<uint8_t> data; ERR_FAIL_COND_V_MSG(!f, data, "File must be opened before use."); @@ -1330,8 +1104,7 @@ Vector<uint8_t> _File::get_buffer(int p_length) const { ERR_FAIL_COND_V_MSG(err != OK, data, "Can't resize data to " + itos(p_length) + " elements."); uint8_t *w = data.ptrw(); - int len = f->get_buffer(&w[0], p_length); - ERR_FAIL_COND_V(len < 0, Vector<uint8_t>()); + int64_t len = f->get_buffer(&w[0], p_length); if (len < p_length) { data.resize(len); @@ -1344,7 +1117,7 @@ String _File::get_as_text() const { ERR_FAIL_COND_V_MSG(!f, String(), "File must be opened before use."); String text; - size_t original_pos = f->get_position(); + uint64_t original_pos = f->get_position(); f->seek(0); String l = get_line(); @@ -1382,15 +1155,15 @@ Vector<String> _File::get_csv_line(const String &p_delim) const { * These flags get reset to false (little endian) on each open */ -void _File::set_endian_swap(bool p_swap) { - eswap = p_swap; +void _File::set_big_endian(bool p_big_endian) { + big_endian = p_big_endian; if (f) { - f->set_endian_swap(p_swap); + f->set_big_endian(p_big_endian); } } -bool _File::get_endian_swap() { - return eswap; +bool _File::is_big_endian() { + return big_endian; } Error _File::get_error() const { @@ -1473,7 +1246,7 @@ void _File::store_csv_line(const Vector<String> &p_values, const String &p_delim void _File::store_buffer(const Vector<uint8_t> &p_buffer) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); - int len = p_buffer.size(); + uint64_t len = p_buffer.size(); if (len == 0) { return; } @@ -1537,7 +1310,7 @@ void _File::_bind_methods() { 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_len"), &_File::get_len); + 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); @@ -1546,14 +1319,14 @@ void _File::_bind_methods() { 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", "len"), &_File::get_buffer); + 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"), &_File::get_as_text); 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("get_endian_swap"), &_File::get_endian_swap); - ClassDB::bind_method(D_METHOD("set_endian_swap", "enable"), &_File::set_endian_swap); + 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)); @@ -1576,7 +1349,7 @@ void _File::_bind_methods() { ClassDB::bind_method(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, "endian_swap"), "set_endian_swap", "get_endian_swap"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "big_endian"), "set_big_endian", "is_big_endian"); BIND_ENUM_CONSTANT(READ); BIND_ENUM_CONSTANT(WRITE); @@ -1617,11 +1390,11 @@ bool _Directory::is_open() const { return d && dir_open; } -Error _Directory::list_dir_begin(bool p_skip_navigational, bool p_skip_hidden) { +Error _Directory::list_dir_begin(bool p_show_navigational, bool p_show_hidden) { ERR_FAIL_COND_V_MSG(!is_open(), ERR_UNCONFIGURED, "Directory must be opened before use."); - _list_skip_navigational = p_skip_navigational; - _list_skip_hidden = p_skip_hidden; + _list_skip_navigational = !p_show_navigational; + _list_skip_hidden = !p_show_hidden; return d->list_dir_begin(); } @@ -1721,9 +1494,9 @@ bool _Directory::dir_exists(String p_dir) { return d->dir_exists(p_dir); } -int _Directory::get_space_left() { - ERR_FAIL_COND_V_MSG(!is_open(), 0, "Directory must be opened before use."); - return d->get_space_left() / 1024 * 1024; //return value in megabytes, given binding is int +uint64_t _Directory::get_space_left() { + ERR_FAIL_COND_V_MSG(!d, 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) { @@ -1759,7 +1532,7 @@ Error _Directory::remove(String p_name) { void _Directory::_bind_methods() { ClassDB::bind_method(D_METHOD("open", "path"), &_Directory::open); - ClassDB::bind_method(D_METHOD("list_dir_begin", "skip_navigational", "skip_hidden"), &_Directory::list_dir_begin, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("list_dir_begin", "show_navigational", "show_hidden"), &_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); @@ -2070,7 +1843,7 @@ Variant _ClassDB::instance(const StringName &p_class) const { return Variant(); } - Reference *r = Object::cast_to<Reference>(obj); + RefCounted *r = Object::cast_to<RefCounted>(obj); if (r) { return REF(r); } else { @@ -2416,12 +2189,12 @@ Variant JSONParseResult::get_result() const { } void _JSON::_bind_methods() { - ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys"), &_JSON::print, DEFVAL(String()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys", "full_precision"), &_JSON::print, DEFVAL(String()), DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse); } -String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys) { - return JSON::print(p_value, p_indent, p_sort_keys); +String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys, bool p_full_precision) { + return JSON::print(p_value, p_indent, p_sort_keys, p_full_precision); } Ref<JSONParseResult> _JSON::parse(const String &p_json) { diff --git a/core/core_bind.h b/core/core_bind.h index 3920116ca4..b161effe95 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -32,11 +32,11 @@ #define CORE_BIND_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" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/os/semaphore.h" #include "core/os/thread.h" @@ -199,14 +199,6 @@ public: void set_use_file_access_save_and_swap(bool p_enable); - Dictionary get_date(bool utc) const; - Dictionary get_time(bool utc) const; - Dictionary get_datetime(bool utc) const; - Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const; - int64_t get_unix_time_from_datetime(Dictionary datetime) const; - Dictionary get_time_zone_info() const; - double get_unix_time() const; - uint64_t get_static_memory_usage() const; uint64_t get_static_memory_peak_usage() const; @@ -237,6 +229,7 @@ public: String get_system_dir(SystemDir p_dir) const; String get_user_data_dir() const; + String get_external_data_dir() const; Error set_thread_name(const String &p_name); Thread::ID get_thread_caller_id() const; @@ -352,11 +345,11 @@ public: _Geometry3D() { singleton = this; } }; -class _File : public Reference { - GDCLASS(_File, Reference); +class _File : public RefCounted { + GDCLASS(_File, RefCounted); FileAccess *f = nullptr; - bool eswap = false; + bool big_endian = false; protected: static void _bind_methods(); @@ -390,8 +383,8 @@ public: 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. - int64_t get_position() const; // Get position in the file. - int64_t get_len() const; // Get size of the 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. @@ -406,20 +399,20 @@ public: Variant get_var(bool p_allow_objects = false) const; - Vector<uint8_t> get_buffer(int p_length) const; // Get an array of bytes. + 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() 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). + /* + * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac). * It's not about the current CPU type but file formats. - * This flags get reset to false (little endian) on each open. + * This flag gets reset to `false` (little endian) on each open. */ - - void set_endian_swap(bool p_swap); - bool get_endian_swap(); + void set_big_endian(bool p_big_endian); + bool is_big_endian(); Error get_error() const; // Get last error. @@ -454,8 +447,8 @@ public: VARIANT_ENUM_CAST(_File::ModeFlags); VARIANT_ENUM_CAST(_File::CompressionMode); -class _Directory : public Reference { - GDCLASS(_Directory, Reference); +class _Directory : public RefCounted { + GDCLASS(_Directory, RefCounted); DirAccess *d; bool dir_open = false; @@ -467,7 +460,7 @@ public: bool is_open() const; - Error list_dir_begin(bool p_skip_navigational = false, bool p_skip_hidden = false); // This starts dir listing. + Error list_dir_begin(bool p_show_navigational = false, bool p_show_hidden = false); // This starts dir listing. String get_next(); bool current_is_dir() const; @@ -486,7 +479,7 @@ public: bool file_exists(String p_file); bool dir_exists(String p_dir); - int get_space_left(); + uint64_t get_space_left(); Error copy(String p_from, String p_to); Error rename(String p_from, String p_to); @@ -524,8 +517,8 @@ public: ~_Marshalls() { singleton = nullptr; } }; -class _Mutex : public Reference { - GDCLASS(_Mutex, Reference); +class _Mutex : public RefCounted { + GDCLASS(_Mutex, RefCounted); Mutex mutex; static void _bind_methods(); @@ -536,8 +529,8 @@ public: void unlock(); }; -class _Semaphore : public Reference { - GDCLASS(_Semaphore, Reference); +class _Semaphore : public RefCounted { + GDCLASS(_Semaphore, RefCounted); Semaphore semaphore; static void _bind_methods(); @@ -548,8 +541,8 @@ public: void post(); }; -class _Thread : public Reference { - GDCLASS(_Thread, Reference); +class _Thread : public RefCounted { + GDCLASS(_Thread, RefCounted); protected: Variant ret; @@ -665,8 +658,8 @@ public: class _JSON; -class JSONParseResult : public Reference { - GDCLASS(JSONParseResult, Reference); +class JSONParseResult : public RefCounted { + GDCLASS(JSONParseResult, RefCounted); friend class _JSON; @@ -705,7 +698,7 @@ protected: public: static _JSON *get_singleton() { return singleton; } - String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false); + String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false, bool p_full_precision = false); Ref<JSONParseResult> parse(const String &p_json); _JSON() { singleton = this; } diff --git a/core/core_constants.cpp b/core/core_constants.cpp index f40928350a..7fc09fc3a6 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -161,7 +161,7 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(KEY_PAGEUP); BIND_CORE_ENUM_CONSTANT(KEY_PAGEDOWN); BIND_CORE_ENUM_CONSTANT(KEY_SHIFT); - BIND_CORE_ENUM_CONSTANT(KEY_CONTROL); + BIND_CORE_ENUM_CONSTANT(KEY_CTRL); BIND_CORE_ENUM_CONSTANT(KEY_META); BIND_CORE_ENUM_CONSTANT(KEY_ALT); BIND_CORE_ENUM_CONSTANT(KEY_CAPSLOCK); @@ -580,10 +580,10 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE); - BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUAT", Variant::QUAT); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS); - BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH); diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h index cc00b18fd2..2f8422f537 100644 --- a/core/crypto/aes_context.h +++ b/core/crypto/aes_context.h @@ -32,10 +32,10 @@ #define AES_CONTEXT_H #include "core/crypto/crypto_core.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class AESContext : public Reference { - GDCLASS(AESContext, Reference); +class AESContext : public RefCounted { + GDCLASS(AESContext, RefCounted); public: enum Mode { diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index 9438fcfea5..a2ccbba58a 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -35,7 +35,7 @@ #include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class CryptoKey : public Resource { GDCLASS(CryptoKey, Resource); @@ -67,8 +67,8 @@ public: virtual Error save(String p_path) = 0; }; -class HMACContext : public Reference { - GDCLASS(HMACContext, Reference); +class HMACContext : public RefCounted { + GDCLASS(HMACContext, RefCounted); protected: static void _bind_methods(); @@ -84,8 +84,8 @@ public: HMACContext() {} }; -class Crypto : public Reference { - GDCLASS(Crypto, Reference); +class Crypto : public RefCounted { + GDCLASS(Crypto, RefCounted); protected: static void _bind_methods(); diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h index 27b380e838..7a2f4df589 100644 --- a/core/crypto/crypto_core.h +++ b/core/crypto/crypto_core.h @@ -31,7 +31,7 @@ #ifndef CRYPTO_CORE_H #define CRYPTO_CORE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class CryptoCore { public: diff --git a/core/crypto/hashing_context.h b/core/crypto/hashing_context.h index 892a48a4e8..31521a147c 100644 --- a/core/crypto/hashing_context.h +++ b/core/crypto/hashing_context.h @@ -31,10 +31,10 @@ #ifndef HASHING_CONTEXT_H #define HASHING_CONTEXT_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class HashingContext : public Reference { - GDCLASS(HashingContext, Reference); +class HashingContext : public RefCounted { + GDCLASS(HashingContext, RefCounted); public: enum HashType { diff --git a/core/debugger/local_debugger.cpp b/core/debugger/local_debugger.cpp index 1dd7e268a5..ab368471e4 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -183,7 +183,7 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { print_line("Error: Unknown option " + key); } else { // Allow explicit tab character - String value = key_value.right(value_pos + 1).replace("\\t", "\t"); + String value = key_value.substr(value_pos + 1).replace("\\t", "\t"); options[key] = value; } @@ -348,7 +348,7 @@ Pair<String, int> LocalDebugger::to_breakpoint(const String &p_line) { } breakpoint.first = script_debugger->breakpoint_find_source(breakpoint_part.left(last_colon).strip_edges()); - breakpoint.second = breakpoint_part.right(last_colon).strip_edges().to_int(); + breakpoint.second = breakpoint_part.substr(last_colon).strip_edges().to_int(); return breakpoint; } diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h index 652e2d9d20..8cba53a81c 100644 --- a/core/debugger/remote_debugger_peer.h +++ b/core/debugger/remote_debugger_peer.h @@ -32,12 +32,12 @@ #define REMOTE_DEBUGGER_PEER_H #include "core/io/stream_peer_tcp.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/os/thread.h" #include "core/string/ustring.h" -class RemoteDebuggerPeer : public Reference { +class RemoteDebuggerPeer : public RefCounted { protected: int max_queued_messages = 4096; diff --git a/core/input/input.cpp b/core/input/input.cpp index 2304c05bf8..6e98b596d7 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -85,7 +85,7 @@ Input *Input::get_singleton() { } void Input::set_mouse_mode(MouseMode p_mode) { - ERR_FAIL_INDEX((int)p_mode, 4); + ERR_FAIL_INDEX((int)p_mode, 5); set_mouse_mode_func(p_mode); } @@ -138,6 +138,7 @@ void Input::_bind_methods() { BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); BIND_ENUM_CONSTANT(MOUSE_MODE_CAPTURED); BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED); + BIND_ENUM_CONSTANT(MOUSE_MODE_CONFINED_HIDDEN); BIND_ENUM_CONSTANT(CURSOR_ARROW); BIND_ENUM_CONSTANT(CURSOR_IBEAM); @@ -1262,16 +1263,16 @@ void Input::parse_mapping(String p_mapping) { } else if (output[0] == '-') { output_range = NEGATIVE_HALF_AXIS; } - output = output.right(1); + output = output.substr(1); } JoyAxisRange input_range = FULL_AXIS; if (input[0] == '+') { input_range = POSITIVE_HALF_AXIS; - input = input.right(1); + input = input.substr(1); } else if (input[0] == '-') { input_range = NEGATIVE_HALF_AXIS; - input = input.right(1); + input = input.substr(1); } bool invert_axis = false; if (input[input.length() - 1] == '~') { @@ -1299,11 +1300,11 @@ void Input::parse_mapping(String p_mapping) { switch (input[0]) { case 'b': binding.inputType = TYPE_BUTTON; - binding.input.button = input.right(1).to_int(); + binding.input.button = input.substr(1).to_int(); break; case 'a': binding.inputType = TYPE_AXIS; - binding.input.axis.axis = input.right(1).to_int(); + binding.input.axis.axis = input.substr(1).to_int(); binding.input.axis.range = input_range; binding.input.axis.invert = invert_axis; break; @@ -1312,7 +1313,7 @@ void Input::parse_mapping(String p_mapping) { String(entry[idx] + "\nInvalid hat input: " + input)); binding.inputType = TYPE_HAT; binding.input.hat.hat = input.substr(1, 1).to_int(); - binding.input.hat.hat_mask = static_cast<HatMask>(input.right(3).to_int()); + binding.input.hat.hat_mask = static_cast<HatMask>(input.substr(3).to_int()); break; default: ERR_CONTINUE_MSG(true, String(entry[idx] + "\nUnrecognised input string: " + input)); diff --git a/core/input/input.h b/core/input/input.h index 99b45db325..ecb4981b13 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -46,7 +46,8 @@ public: MOUSE_MODE_VISIBLE, MOUSE_MODE_HIDDEN, MOUSE_MODE_CAPTURED, - MOUSE_MODE_CONFINED + MOUSE_MODE_CONFINED, + MOUSE_MODE_CONFINED_HIDDEN, }; #undef CursorShape diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 46629d742e..9c1cf15342 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -147,66 +147,66 @@ bool InputEventWithModifiers::is_storing_command() const { return store_command; } -void InputEventWithModifiers::set_shift(bool p_enabled) { - shift = p_enabled; +void InputEventWithModifiers::set_shift_pressed(bool p_enabled) { + shift_pressed = p_enabled; } -bool InputEventWithModifiers::get_shift() const { - return shift; +bool InputEventWithModifiers::is_shift_pressed() const { + return shift_pressed; } -void InputEventWithModifiers::set_alt(bool p_enabled) { - alt = p_enabled; +void InputEventWithModifiers::set_alt_pressed(bool p_enabled) { + alt_pressed = p_enabled; } -bool InputEventWithModifiers::get_alt() const { - return alt; +bool InputEventWithModifiers::is_alt_pressed() const { + return alt_pressed; } -void InputEventWithModifiers::set_control(bool p_enabled) { - control = p_enabled; +void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) { + ctrl_pressed = p_enabled; } -bool InputEventWithModifiers::get_control() const { - return control; +bool InputEventWithModifiers::is_ctrl_pressed() const { + return ctrl_pressed; } -void InputEventWithModifiers::set_metakey(bool p_enabled) { - meta = p_enabled; +void InputEventWithModifiers::set_meta_pressed(bool p_enabled) { + meta_pressed = p_enabled; } -bool InputEventWithModifiers::get_metakey() const { - return meta; +bool InputEventWithModifiers::is_meta_pressed() const { + return meta_pressed; } -void InputEventWithModifiers::set_command(bool p_enabled) { - command = p_enabled; +void InputEventWithModifiers::set_command_pressed(bool p_enabled) { + command_pressed = p_enabled; } -bool InputEventWithModifiers::get_command() const { - return command; +bool InputEventWithModifiers::is_command_pressed() const { + return command_pressed; } void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModifiers *event) { - set_alt(event->get_alt()); - set_shift(event->get_shift()); - set_control(event->get_control()); - set_metakey(event->get_metakey()); + set_alt_pressed(event->is_alt_pressed()); + set_shift_pressed(event->is_shift_pressed()); + set_ctrl_pressed(event->is_ctrl_pressed()); + set_meta_pressed(event->is_meta_pressed()); } String InputEventWithModifiers::as_text() const { Vector<String> mod_names; - if (get_control()) { - mod_names.push_back(find_keycode_name(KEY_CONTROL)); + if (is_ctrl_pressed()) { + mod_names.push_back(find_keycode_name(KEY_CTRL)); } - if (get_shift()) { + if (is_shift_pressed()) { mod_names.push_back(find_keycode_name(KEY_SHIFT)); } - if (get_alt()) { + if (is_alt_pressed()) { mod_names.push_back(find_keycode_name(KEY_ALT)); } - if (get_metakey()) { + if (is_meta_pressed()) { mod_names.push_back(find_keycode_name(KEY_META)); } @@ -225,27 +225,27 @@ void InputEventWithModifiers::_bind_methods() { ClassDB::bind_method(D_METHOD("set_store_command", "enable"), &InputEventWithModifiers::set_store_command); ClassDB::bind_method(D_METHOD("is_storing_command"), &InputEventWithModifiers::is_storing_command); - ClassDB::bind_method(D_METHOD("set_alt", "enable"), &InputEventWithModifiers::set_alt); - ClassDB::bind_method(D_METHOD("get_alt"), &InputEventWithModifiers::get_alt); + ClassDB::bind_method(D_METHOD("set_alt_pressed", "pressed"), &InputEventWithModifiers::set_alt_pressed); + ClassDB::bind_method(D_METHOD("is_alt_pressed"), &InputEventWithModifiers::is_alt_pressed); - ClassDB::bind_method(D_METHOD("set_shift", "enable"), &InputEventWithModifiers::set_shift); - ClassDB::bind_method(D_METHOD("get_shift"), &InputEventWithModifiers::get_shift); + ClassDB::bind_method(D_METHOD("set_shift_pressed", "pressed"), &InputEventWithModifiers::set_shift_pressed); + ClassDB::bind_method(D_METHOD("is_shift_pressed"), &InputEventWithModifiers::is_shift_pressed); - ClassDB::bind_method(D_METHOD("set_control", "enable"), &InputEventWithModifiers::set_control); - ClassDB::bind_method(D_METHOD("get_control"), &InputEventWithModifiers::get_control); + ClassDB::bind_method(D_METHOD("set_ctrl_pressed", "pressed"), &InputEventWithModifiers::set_ctrl_pressed); + ClassDB::bind_method(D_METHOD("is_ctrl_pressed"), &InputEventWithModifiers::is_ctrl_pressed); - ClassDB::bind_method(D_METHOD("set_metakey", "enable"), &InputEventWithModifiers::set_metakey); - ClassDB::bind_method(D_METHOD("get_metakey"), &InputEventWithModifiers::get_metakey); + ClassDB::bind_method(D_METHOD("set_meta_pressed", "pressed"), &InputEventWithModifiers::set_meta_pressed); + ClassDB::bind_method(D_METHOD("is_meta_pressed"), &InputEventWithModifiers::is_meta_pressed); - ClassDB::bind_method(D_METHOD("set_command", "enable"), &InputEventWithModifiers::set_command); - ClassDB::bind_method(D_METHOD("get_command"), &InputEventWithModifiers::get_command); + ClassDB::bind_method(D_METHOD("set_command_pressed", "pressed"), &InputEventWithModifiers::set_command_pressed); + ClassDB::bind_method(D_METHOD("is_command_pressed"), &InputEventWithModifiers::is_command_pressed); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "store_command"), "set_store_command", "is_storing_command"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt"), "set_alt", "get_alt"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift"), "set_shift", "get_shift"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "control"), "set_control", "get_control"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta"), "set_metakey", "get_metakey"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command"), "set_command", "get_command"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alt_pressed"), "set_alt_pressed", "is_alt_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shift_pressed"), "set_shift_pressed", "is_shift_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ctrl_pressed"), "set_ctrl_pressed", "is_ctrl_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_pressed"), "set_meta_pressed", "is_meta_pressed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_pressed"), "set_command_pressed", "is_command_pressed"); } void InputEventWithModifiers::_validate_property(PropertyInfo &property) const { @@ -253,18 +253,18 @@ void InputEventWithModifiers::_validate_property(PropertyInfo &property) const { // If we only want to Store "Command". #ifdef APPLE_STYLE_KEYS // Don't store "Meta" on Mac. - if (property.name == "meta") { + if (property.name == "meta_pressed") { property.usage ^= PROPERTY_USAGE_STORAGE; } #else - // Don't store "Control". - if (property.name == "control") { + // Don't store "Ctrl". + if (property.name == "ctrl_pressed") { property.usage ^= PROPERTY_USAGE_STORAGE; } #endif } else { - // We don't want to store command, only control or meta (on mac). - if (property.name == "command") { + // We don't want to store command, only ctrl or meta (on mac). + if (property.name == "command_pressed") { property.usage ^= PROPERTY_USAGE_STORAGE; } } @@ -314,16 +314,16 @@ bool InputEventKey::is_echo() const { uint32_t InputEventKey::get_keycode_with_modifiers() const { uint32_t sc = keycode; - if (get_control()) { + if (is_ctrl_pressed()) { sc |= KEY_MASK_CTRL; } - if (get_alt()) { + if (is_alt_pressed()) { sc |= KEY_MASK_ALT; } - if (get_shift()) { + if (is_shift_pressed()) { sc |= KEY_MASK_SHIFT; } - if (get_metakey()) { + if (is_meta_pressed()) { sc |= KEY_MASK_META; } @@ -332,16 +332,16 @@ uint32_t InputEventKey::get_keycode_with_modifiers() const { uint32_t InputEventKey::get_physical_keycode_with_modifiers() const { uint32_t sc = physical_keycode; - if (get_control()) { + if (is_ctrl_pressed()) { sc |= KEY_MASK_CTRL; } - if (get_alt()) { + if (is_alt_pressed()) { sc |= KEY_MASK_ALT; } - if (get_shift()) { + if (is_shift_pressed()) { sc |= KEY_MASK_SHIFT; } - if (get_metakey()) { + if (is_meta_pressed()) { sc |= KEY_MASK_META; } @@ -372,16 +372,16 @@ String InputEventKey::to_string() { String kc = ""; String physical = "false"; if (keycode == 0) { - kc = itos(physical_keycode) + " " + keycode_get_string(physical_keycode); + kc = itos(physical_keycode) + " (" + keycode_get_string(physical_keycode) + ")"; physical = "true"; } else { - kc = itos(keycode) + " " + keycode_get_string(keycode); + kc = itos(keycode) + " (" + keycode_get_string(keycode) + ")"; } String mods = InputEventWithModifiers::as_text(); - mods = mods == "" ? TTR("None") : mods; + mods = mods == "" ? TTR("none") : mods; - return vformat("InputEventKey: keycode=%s mods=%s physical=%s pressed=%s echo=%s", kc, mods, physical, p, e); + return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, pressed=%s, echo=%s", kc, mods, physical, p, e); } Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) { @@ -391,19 +391,19 @@ Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) { ie->set_unicode(p_keycode & KEY_CODE_MASK); if (p_keycode & KEY_MASK_SHIFT) { - ie->set_shift(true); + ie->set_shift_pressed(true); } if (p_keycode & KEY_MASK_ALT) { - ie->set_alt(true); + ie->set_alt_pressed(true); } if (p_keycode & KEY_MASK_CTRL) { - ie->set_control(true); + ie->set_ctrl_pressed(true); } if (p_keycode & KEY_MASK_CMD) { - ie->set_command(true); + ie->set_command_pressed(true); } if (p_keycode & KEY_MASK_META) { - ie->set_metakey(true); + ie->set_meta_pressed(true); } return ie; @@ -667,11 +667,11 @@ String InputEventMouseButton::to_string() { } String mods = InputEventWithModifiers::as_text(); - mods = mods == "" ? TTR("None") : mods; + mods = mods == "" ? TTR("none") : mods; // Work around the fact vformat can only take 5 substitutions but 6 need to be passed. - String index_and_mods = vformat("button_index=%s mods=%s", button_index, mods); - return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s double_click=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d); + String index_and_mods = vformat("button_index=%s, mods=%s", button_index, mods); + return vformat("InputEventMouseButton: %s, pressed=%s, position=(%s), button_mask=%d, double_click=%s", index_and_mods, p, String(get_position()), get_button_mask(), d); } void InputEventMouseButton::_bind_methods() { @@ -780,7 +780,9 @@ String InputEventMouseMotion::to_string() { break; } - return "InputEventMouseMotion : button_mask=" + button_mask_string + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + "), pressure=(" + rtos(get_pressure()) + "), tilt=(" + String(get_tilt()) + ")"; + // Work around the fact vformat can only take 5 substitutions but 6 need to be passed. + String mask_and_position = vformat("button_mask=%s, position=(%s)", button_mask_string, String(get_position())); + return vformat("InputEventMouseMotion: %s, relative=(%s), speed=(%s), pressure=%.2f, tilt=(%s)", mask_and_position, String(get_relative()), String(get_speed()), get_pressure(), String(get_tilt())); } bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) { @@ -801,19 +803,19 @@ bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) { return false; } - if (get_shift() != motion->get_shift()) { + if (is_shift_pressed() != motion->is_shift_pressed()) { return false; } - if (get_control() != motion->get_control()) { + if (is_ctrl_pressed() != motion->is_ctrl_pressed()) { return false; } - if (get_alt() != motion->get_alt()) { + if (is_alt_pressed() != motion->is_alt_pressed()) { return false; } - if (get_metakey() != motion->get_metakey()) { + if (is_meta_pressed() != motion->is_meta_pressed()) { return false; } @@ -918,11 +920,11 @@ static const char *_joy_axis_descriptions[JOY_AXIS_MAX] = { String InputEventJoypadMotion::as_text() const { String desc = axis < JOY_AXIS_MAX ? RTR(_joy_axis_descriptions[axis]) : TTR("Unknown Joypad Axis"); - return vformat(TTR("Joypad Motion on Axis %s (%s) with Value %s"), itos(axis), desc, String(Variant(axis_value))); + return vformat(TTR("Joypad Motion on Axis %d (%s) with Value %.2f"), axis, desc, axis_value); } String InputEventJoypadMotion::to_string() { - return "InputEventJoypadMotion : axis=" + itos(axis) + ", axis_value=" + String(Variant(axis_value)); + return vformat("InputEventJoypadMotion: axis=%d, axis_value=%.2f", axis, axis_value); } void InputEventJoypadMotion::_bind_methods() { @@ -1021,7 +1023,7 @@ static const char *_joy_button_descriptions[JOY_BUTTON_SDL_MAX] = { String InputEventJoypadButton::as_text() const { String text = "Joypad Button " + itos(button_index); - if (button_index < JOY_BUTTON_SDL_MAX) { + if (button_index >= 0 && button_index < JOY_BUTTON_SDL_MAX) { text += vformat(" (%s)", _joy_button_descriptions[button_index]); } @@ -1033,7 +1035,8 @@ String InputEventJoypadButton::as_text() const { } String InputEventJoypadButton::to_string() { - return "InputEventJoypadButton : button_index=" + itos(button_index) + ", pressed=" + (pressed ? "true" : "false") + ", pressure=" + String(Variant(pressure)); + String p = pressed ? "true" : "false"; + return vformat("InputEventJoypadButton: button_index=%d, pressed=%s, pressure=%.2f", button_index, p, pressure); } Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(int p_btn_index) { @@ -1104,7 +1107,8 @@ String InputEventScreenTouch::as_text() const { } String InputEventScreenTouch::to_string() { - return "InputEventScreenTouch : index=" + itos(index) + ", pressed=" + (pressed ? "true" : "false") + ", position=(" + String(get_position()) + ")"; + String p = pressed ? "true" : "false"; + return vformat("InputEventScreenTouch: index=%d, pressed=%s, position=(%s)", index, p, String(get_position())); } void InputEventScreenTouch::_bind_methods() { @@ -1177,7 +1181,7 @@ String InputEventScreenDrag::as_text() const { } String InputEventScreenDrag::to_string() { - return "InputEventScreenDrag : index=" + itos(index) + ", position=(" + String(get_position()) + "), relative=(" + String(get_relative()) + "), speed=(" + String(get_speed()) + ")"; + return vformat("InputEventScreenDrag: index=%d, position=(%s), relative=(%s), speed=(%s)", index, String(get_position()), String(get_relative()), String(get_speed())); } void InputEventScreenDrag::_bind_methods() { @@ -1264,7 +1268,8 @@ String InputEventAction::as_text() const { } String InputEventAction::to_string() { - return "InputEventAction : action=" + action + ", pressed=(" + (pressed ? "true" : "false"); + String p = pressed ? "true" : "false"; + return vformat("InputEventAction: action=\"%s\", pressed=%s", action, p); } void InputEventAction::_bind_methods() { @@ -1331,7 +1336,7 @@ String InputEventMagnifyGesture::as_text() const { } String InputEventMagnifyGesture::to_string() { - return "InputEventMagnifyGesture : factor=" + rtos(get_factor()) + ", position=(" + String(get_position()) + ")"; + return vformat("InputEventMagnifyGesture: factor=%.2f, position=(%s)", factor, String(get_position())); } void InputEventMagnifyGesture::_bind_methods() { @@ -1371,7 +1376,7 @@ String InputEventPanGesture::as_text() const { } String InputEventPanGesture::to_string() { - return "InputEventPanGesture : delta=(" + String(get_delta()) + "), position=(" + String(get_position()) + ")"; + return vformat("InputEventPanGesture: delta=(%s), position=(%s)", String(get_delta()), String(get_position())); } void InputEventPanGesture::_bind_methods() { @@ -1452,7 +1457,7 @@ String InputEventMIDI::as_text() const { } String InputEventMIDI::to_string() { - return vformat("InputEvenMIDI: channel=%s message=%s pitch=%s velocity=%s pressure=%s", itos(channel), itos(message), itos(pitch), itos(velocity), itos(pressure)); + return vformat("InputEventMIDI: channel=%d, message=%d, pitch=%d, velocity=%d, pressure=%d", channel, message, pitch, velocity, pressure); } void InputEventMIDI::_bind_methods() { diff --git a/core/input/input_event.h b/core/input/input_event.h index 5a33ee7b9c..eed0d79326 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -170,21 +170,21 @@ class InputEventWithModifiers : public InputEventFromWindow { bool store_command = true; - bool shift = false; - bool alt = false; + bool shift_pressed = false; + bool alt_pressed = false; #ifdef APPLE_STYLE_KEYS union { - bool command; - bool meta = false; //< windows/mac key + bool command_pressed; + bool meta_pressed = false; //< windows/mac key }; - bool control = false; + bool ctrl_pressed = false; #else union { - bool command; //< windows/mac key - bool control = false; + bool command_pressed; //< windows/mac key + bool ctrl_pressed = false; }; - bool meta = false; //< windows/mac key + bool meta_pressed = false; //< windows/mac key #endif protected: @@ -195,20 +195,20 @@ public: void set_store_command(bool p_enabled); bool is_storing_command() const; - void set_shift(bool p_enabled); - bool get_shift() const; + void set_shift_pressed(bool p_pressed); + bool is_shift_pressed() const; - void set_alt(bool p_enabled); - bool get_alt() const; + void set_alt_pressed(bool p_pressed); + bool is_alt_pressed() const; - void set_control(bool p_enabled); - bool get_control() const; + void set_ctrl_pressed(bool p_pressed); + bool is_ctrl_pressed() const; - void set_metakey(bool p_enabled); - bool get_metakey() const; + void set_meta_pressed(bool p_pressed); + bool is_meta_pressed() const; - void set_command(bool p_enabled); - bool get_command() const; + void set_command_pressed(bool p_pressed); + bool is_command_pressed() const; void set_modifiers_from_event(const InputEventWithModifiers *event); diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 7421909650..5b96babe44 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -166,7 +166,7 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object."); ERR_FAIL_COND_MSG(!input_map.has(p_action), _suggest_actions(p_action)); if (_find_event(input_map[p_action], p_event, true)) { - return; // Already addded. + return; // Already added. } input_map[p_action].inputs.push_back(p_event); @@ -353,6 +353,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_text_scroll_down", TTRC("Scroll Down") }, { "ui_text_scroll_down.OSX", TTRC("Scroll Down") }, { "ui_text_select_all", TTRC("Select All") }, + { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") }, { "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") }, { "ui_graph_duplicate", TTRC("Duplicate Nodes") }, { "ui_graph_delete", TTRC("Delete Nodes") }, @@ -473,10 +474,14 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { default_builtin_cache.insert("ui_text_completion_query", inputs); inputs = List<Ref<InputEvent>>(); - inputs.push_back(InputEventKey::create_reference(KEY_TAB)); inputs.push_back(InputEventKey::create_reference(KEY_ENTER)); + inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER)); default_builtin_cache.insert("ui_text_completion_accept", inputs); + inputs = List<Ref<InputEvent>>(); + inputs.push_back(InputEventKey::create_reference(KEY_TAB)); + default_builtin_cache.insert("ui_text_completion_replace", inputs); + // Newlines inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(KEY_ENTER)); @@ -506,6 +511,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { // Text Backspace and Delete inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE)); + inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_SHIFT)); default_builtin_cache.insert("ui_text_backspace", inputs); inputs = List<Ref<InputEvent>>(); @@ -651,6 +657,10 @@ const OrderedHashMap<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 | KEY_MASK_CMD)); + default_builtin_cache.insert("ui_text_select_word_under_caret", 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/config_file.h b/core/io/config_file.h index 1b28257c60..dbba43ace5 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -31,13 +31,13 @@ #ifndef CONFIG_FILE_H #define CONFIG_FILE_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "core/templates/ordered_hash_map.h" #include "core/variant/variant_parser.h" -class ConfigFile : public Reference { - GDCLASS(ConfigFile, Reference); +class ConfigFile : public RefCounted { + GDCLASS(ConfigFile, RefCounted); OrderedHashMap<String, OrderedHashMap<String, Variant>> values; diff --git a/core/os/dir_access.cpp b/core/io/dir_access.cpp index b7c3a17ba9..dfba00067f 100644 --- a/core/os/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -31,7 +31,7 @@ #include "dir_access.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/memory.h" #include "core/os/os.h" @@ -331,7 +331,7 @@ public: } }; -Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags) { +Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) { List<String> dirs; String curdir = get_current_dir(); @@ -339,7 +339,9 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag String n = get_next(); while (n != String()) { if (n != "." && n != "..") { - if (current_is_dir()) { + if (p_copy_links && is_link(get_current_dir().plus_file(n))) { + create_link(read_link(get_current_dir().plus_file(n)), p_to + n); + } else if (current_is_dir()) { dirs.push_back(n); } else { const String &rel_path = n; @@ -371,7 +373,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag Error err = change_dir(E->get()); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + E->get() + "'."); - err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags); + err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links); if (err) { change_dir(".."); ERR_FAIL_V_MSG(err, "Failed to copy recursively."); @@ -383,7 +385,7 @@ Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flag return OK; } -Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) { +Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) { ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist."); DirAccess *target_da = DirAccess::create_for_path(p_to); @@ -402,7 +404,7 @@ Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags) { } DirChanger dir_changer(this, p_from); - Error err = _copy_dir(target_da, p_to, p_chmod_flags); + Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links); memdelete(target_da); return err; diff --git a/core/os/dir_access.h b/core/io/dir_access.h index 7f0bcd372d..16154a4850 100644 --- a/core/os/dir_access.h +++ b/core/io/dir_access.h @@ -50,7 +50,7 @@ private: AccessType _access_type = ACCESS_FILESYSTEM; static CreateFunc create_func[ACCESS_MAX]; ///< set this to instance a filesystem object - Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags); + Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links); protected: String _get_root_path() const; @@ -87,13 +87,17 @@ public: virtual bool is_readable(String p_dir) { return true; }; virtual bool is_writable(String p_dir) { return true; }; static bool exists(String p_dir); - virtual size_t get_space_left() = 0; + virtual uint64_t get_space_left() = 0; - Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1); + Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1, bool p_copy_links = false); virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1); virtual Error rename(String p_from, String p_to) = 0; virtual Error remove(String p_name) = 0; + virtual bool is_link(String p_file) = 0; + virtual String read_link(String p_file) = 0; + virtual Error create_link(String p_source, String p_target) = 0; + // Meant for editor code when we want to quickly remove a file without custom // handling (e.g. removing a cache file). static void remove_file_or_error(String p_path) { diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp index 288b2efe0e..655fb18535 100644 --- a/core/io/dtls_server.cpp +++ b/core/io/dtls_server.cpp @@ -31,7 +31,7 @@ #include "dtls_server.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" DTLSServer *(*DTLSServer::_create)() = nullptr; bool DTLSServer::available = false; diff --git a/core/io/dtls_server.h b/core/io/dtls_server.h index 92b6caf508..02a32533e1 100644 --- a/core/io/dtls_server.h +++ b/core/io/dtls_server.h @@ -34,8 +34,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer_dtls.h" -class DTLSServer : public Reference { - GDCLASS(DTLSServer, Reference); +class DTLSServer : public RefCounted { + GDCLASS(DTLSServer, RefCounted); protected: static DTLSServer *(*_create)(); diff --git a/core/os/file_access.cpp b/core/io/file_access.cpp index ad234c2d49..d21c0bd9a2 100644 --- a/core/os/file_access.cpp +++ b/core/io/file_access.cpp @@ -164,7 +164,7 @@ uint16_t FileAccess::get_16() const { a = get_8(); b = get_8(); - if (endian_swap) { + if (big_endian) { SWAP(a, b); } @@ -182,7 +182,7 @@ uint32_t FileAccess::get_32() const { a = get_16(); b = get_16(); - if (endian_swap) { + if (big_endian) { SWAP(a, b); } @@ -200,7 +200,7 @@ uint64_t FileAccess::get_64() const { a = get_32(); b = get_32(); - if (endian_swap) { + if (big_endian) { SWAP(a, b); } @@ -367,10 +367,10 @@ Vector<String> FileAccess::get_csv_line(const String &p_delim) const { return strings; } -int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); - int i = 0; + + uint64_t i = 0; for (i = 0; i < p_length && !eof_reached(); i++) { p_dst[i] = get_8(); } @@ -380,11 +380,11 @@ int FileAccess::get_buffer(uint8_t *p_dst, int p_length) const { String FileAccess::get_as_utf8_string() const { Vector<uint8_t> sourcef; - int len = get_len(); + uint64_t len = get_length(); sourcef.resize(len + 1); uint8_t *w = sourcef.ptrw(); - int r = get_buffer(w, len); + uint64_t r = get_buffer(w, len); ERR_FAIL_COND_V(r != len, String()); w[len] = 0; @@ -401,7 +401,7 @@ void FileAccess::store_16(uint16_t p_dest) { a = p_dest & 0xFF; b = p_dest >> 8; - if (endian_swap) { + if (big_endian) { SWAP(a, b); } @@ -415,7 +415,7 @@ void FileAccess::store_32(uint32_t p_dest) { a = p_dest & 0xFFFF; b = p_dest >> 16; - if (endian_swap) { + if (big_endian) { SWAP(a, b); } @@ -429,7 +429,7 @@ void FileAccess::store_64(uint64_t p_dest) { a = p_dest & 0xFFFFFFFF; b = p_dest >> 32; - if (endian_swap) { + if (big_endian) { SWAP(a, b); } @@ -550,8 +550,9 @@ void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_ store_line(line); } -void FileAccess::store_buffer(const uint8_t *p_src, int p_length) { - for (int i = 0; i < p_length; i++) { +void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); + for (uint64_t i = 0; i < p_length; i++) { store_8(p_src[i]); } } @@ -565,7 +566,7 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err ERR_FAIL_V_MSG(Vector<uint8_t>(), "Can't open file from path '" + String(p_path) + "'."); } Vector<uint8_t> data; - data.resize(f->get_len()); + data.resize(f->get_length()); f->get_buffer(data.ptrw(), data.size()); memdelete(f); return data; @@ -601,7 +602,7 @@ String FileAccess::get_md5(const String &p_file) { unsigned char step[32768]; while (true) { - int br = f->get_buffer(step, 32768); + uint64_t br = f->get_buffer(step, 32768); if (br > 0) { ctx.update(step, br); } @@ -629,7 +630,7 @@ String FileAccess::get_multiple_md5(const Vector<String> &p_file) { unsigned char step[32768]; while (true) { - int br = f->get_buffer(step, 32768); + uint64_t br = f->get_buffer(step, 32768); if (br > 0) { ctx.update(step, br); } @@ -658,7 +659,7 @@ String FileAccess::get_sha256(const String &p_file) { unsigned char step[32768]; while (true) { - int br = f->get_buffer(step, 32768); + uint64_t br = f->get_buffer(step, 32768); if (br > 0) { ctx.update(step, br); } diff --git a/core/os/file_access.h b/core/io/file_access.h index 1c78204c1d..5804aa2c47 100644 --- a/core/os/file_access.h +++ b/core/io/file_access.h @@ -52,7 +52,7 @@ public: typedef void (*FileCloseFailNotify)(const String &); typedef FileAccess *(*CreateFunc)(); - bool endian_swap = false; + bool big_endian = false; bool real_is_double = false; virtual uint32_t _get_unix_permissions(const String &p_file) = 0; @@ -93,10 +93,10 @@ public: virtual String get_path() const { return ""; } /// returns the path for the current open file virtual String get_path_absolute() const { return ""; } /// returns the absolute path for the current open file - virtual void seek(size_t p_position) = 0; ///< seek to a given position - virtual void seek_end(int64_t p_position = 0) = 0; ///< seek from the end of file - virtual size_t get_position() const = 0; ///< get position in the file - virtual size_t get_len() const = 0; ///< get size of the file + virtual void seek(uint64_t p_position) = 0; ///< seek to a given position + virtual void seek_end(int64_t p_position = 0) = 0; ///< seek from the end of file with negative offset + virtual uint64_t get_position() const = 0; ///< get position in the file + virtual uint64_t get_length() const = 0; ///< get size of the file virtual bool eof_reached() const = 0; ///< reading passed EOF @@ -109,19 +109,19 @@ public: virtual double get_double() const; virtual real_t get_real() const; - virtual int get_buffer(uint8_t *p_dst, int p_length) const; ///< get an array of bytes + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes virtual String get_line() const; virtual String get_token() const; virtual Vector<String> get_csv_line(const String &p_delim = ",") const; virtual String get_as_utf8_string() const; - /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) + /** + * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) * It's not about the current CPU type but file formats. - * this flags get reset to false (little endian) on each open + * This flag gets reset to `false` (little endian) on each open. */ - - virtual void set_endian_swap(bool p_swap) { endian_swap = p_swap; } - inline bool get_endian_swap() const { return endian_swap; } + virtual void set_big_endian(bool p_big_endian) { big_endian = p_big_endian; } + inline bool is_big_endian() const { return big_endian; } virtual Error get_error() const = 0; ///< get last error @@ -142,7 +142,7 @@ public: virtual void store_pascal_string(const String &p_string); virtual String get_pascal_string(); - virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes virtual bool file_exists(const String &p_name) = 0; ///< return true if a file exists diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index b2440629e3..e54c947340 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -32,7 +32,7 @@ #include "core/string/print_string.h" -void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, int p_block_size) { +void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_mode, uint32_t p_block_size) { magic = p_magic.ascii().get_data(); if (magic.length() > 4) { magic = magic.substr(0, 4); @@ -67,10 +67,10 @@ Error FileAccessCompressed::open_after_magic(FileAccess *p_base) { ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Can't open compressed file '" + p_base->get_path() + "' with block size 0, it is corrupted."); } read_total = f->get_32(); - int bc = (read_total / block_size) + 1; - int acc_ofs = f->get_position() + bc * 4; - int max_bs = 0; - for (int i = 0; i < bc; i++) { + uint32_t bc = (read_total / block_size) + 1; + uint64_t acc_ofs = f->get_position() + bc * 4; + uint32_t max_bs = 0; + for (uint32_t i = 0; i < bc; i++) { ReadBlock rb; rb.offset = acc_ofs; rb.csize = f->get_32(); @@ -148,15 +148,15 @@ void FileAccessCompressed::close() { f->store_32(cmode); //write compression mode 4 f->store_32(block_size); //write block size 4 f->store_32(write_max); //max amount of data written 4 - int bc = (write_max / block_size) + 1; + uint32_t bc = (write_max / block_size) + 1; - for (int i = 0; i < bc; i++) { + for (uint32_t i = 0; i < bc; i++) { f->store_32(0); //compressed sizes, will update later } Vector<int> block_sizes; - for (int i = 0; i < bc; i++) { - int bl = i == (bc - 1) ? write_max % block_size : block_size; + for (uint32_t i = 0; i < bc; i++) { + uint32_t bl = i == (bc - 1) ? write_max % block_size : block_size; uint8_t *bp = &write_ptr[i * block_size]; Vector<uint8_t> cblock; @@ -168,7 +168,7 @@ void FileAccessCompressed::close() { } f->seek(16); //ok write block sizes - for (int i = 0; i < bc; i++) { + for (uint32_t i = 0; i < bc; i++) { f->store_32(block_sizes[i]); } f->seek_end(); @@ -190,8 +190,9 @@ bool FileAccessCompressed::is_open() const { return f != nullptr; } -void FileAccessCompressed::seek(size_t p_position) { +void FileAccessCompressed::seek(uint64_t p_position) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + if (writing) { ERR_FAIL_COND(p_position > write_max); @@ -204,7 +205,7 @@ void FileAccessCompressed::seek(size_t p_position) { } else { at_end = false; read_eof = false; - int block_idx = p_position / block_size; + uint32_t block_idx = p_position / block_size; if (block_idx != read_block) { read_block = block_idx; f->seek(read_blocks[read_block].offset); @@ -227,7 +228,7 @@ void FileAccessCompressed::seek_end(int64_t p_position) { } } -size_t FileAccessCompressed::get_position() const { +uint64_t FileAccessCompressed::get_position() const { ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); if (writing) { return write_pos; @@ -236,7 +237,7 @@ size_t FileAccessCompressed::get_position() const { } } -size_t FileAccessCompressed::get_len() const { +uint64_t FileAccessCompressed::get_length() const { ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); if (writing) { return write_max; @@ -285,9 +286,8 @@ uint8_t FileAccessCompressed::get_8() const { return ret; } -int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccessCompressed::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use."); ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode."); @@ -296,7 +296,7 @@ int FileAccessCompressed::get_buffer(uint8_t *p_dst, int p_length) const { return 0; } - for (int i = 0; i < p_length; i++) { + for (uint64_t i = 0; i < p_length; i++) { p_dst[i] = read_ptr[read_pos]; read_pos++; if (read_pos >= read_block_size) { diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index 118d05ea57..3389e020e3 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -32,39 +32,39 @@ #define FILE_ACCESS_COMPRESSED_H #include "core/io/compression.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" class FileAccessCompressed : public FileAccess { Compression::Mode cmode = Compression::MODE_ZSTD; bool writing = false; - uint32_t write_pos = 0; + uint64_t write_pos = 0; uint8_t *write_ptr = nullptr; uint32_t write_buffer_size = 0; - uint32_t write_max = 0; + uint64_t write_max = 0; uint32_t block_size = 0; mutable bool read_eof = false; mutable bool at_end = false; struct ReadBlock { - int csize; - int offset; + uint32_t csize; + uint64_t offset; }; mutable Vector<uint8_t> comp_buffer; uint8_t *read_ptr = nullptr; - mutable int read_block = 0; - int read_block_count = 0; - mutable int read_block_size = 0; - mutable int read_pos = 0; + mutable uint32_t read_block = 0; + uint32_t read_block_count = 0; + mutable uint32_t read_block_size = 0; + mutable uint64_t read_pos = 0; Vector<ReadBlock> read_blocks; - uint32_t read_total = 0; + uint64_t read_total = 0; String magic = "GCMP"; mutable Vector<uint8_t> buffer; FileAccess *f = nullptr; public: - void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, int p_block_size = 4096); + void configure(const String &p_magic, Compression::Mode p_mode = Compression::MODE_ZSTD, uint32_t p_block_size = 4096); Error open_after_magic(FileAccess *p_base); @@ -72,15 +72,15 @@ public: virtual void close(); ///< close a file virtual bool is_open() const; ///< true when file is open - virtual void seek(size_t p_position); ///< seek to a given position + virtual void seek(uint64_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual uint64_t get_position() const; ///< get position in the file + virtual uint64_t get_length() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; virtual Error get_error() const; ///< get last error diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 13377a3a25..9e316291e8 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -69,14 +69,14 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8 } base = p_base->get_position(); - ERR_FAIL_COND_V(p_base->get_len() < base + length, ERR_FILE_CORRUPT); - uint32_t ds = length; + ERR_FAIL_COND_V(p_base->get_length() < base + length, ERR_FILE_CORRUPT); + uint64_t ds = length; if (ds % 16) { ds += 16 - (ds % 16); } data.resize(ds); - uint32_t blen = p_base->get_buffer(data.ptrw(), ds); + uint64_t blen = p_base->get_buffer(data.ptrw(), ds); ERR_FAIL_COND_V(blen != ds, ERR_FILE_CORRUPT); { @@ -141,7 +141,7 @@ void FileAccessEncrypted::release() { void FileAccessEncrypted::_release() { if (writing) { Vector<uint8_t> compressed; - size_t len = data.size(); + uint64_t len = data.size(); if (len % 16) { len += 16 - (len % 16); } @@ -198,9 +198,9 @@ String FileAccessEncrypted::get_path_absolute() const { } } -void FileAccessEncrypted::seek(size_t p_position) { - if (p_position > (size_t)data.size()) { - p_position = data.size(); +void FileAccessEncrypted::seek(uint64_t p_position) { + if (p_position > get_length()) { + p_position = get_length(); } pos = p_position; @@ -208,14 +208,14 @@ void FileAccessEncrypted::seek(size_t p_position) { } void FileAccessEncrypted::seek_end(int64_t p_position) { - seek(data.size() + p_position); + seek(get_length() + p_position); } -size_t FileAccessEncrypted::get_position() const { +uint64_t FileAccessEncrypted::get_position() const { return pos; } -size_t FileAccessEncrypted::get_len() const { +uint64_t FileAccessEncrypted::get_length() const { return data.size(); } @@ -225,7 +225,7 @@ bool FileAccessEncrypted::eof_reached() const { uint8_t FileAccessEncrypted::get_8() const { ERR_FAIL_COND_V_MSG(writing, 0, "File has not been opened in read mode."); - if (pos >= data.size()) { + if (pos >= get_length()) { eofed = true; return 0; } @@ -235,13 +235,12 @@ uint8_t FileAccessEncrypted::get_8() const { return b; } -int FileAccessEncrypted::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccessEncrypted::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); ERR_FAIL_COND_V_MSG(writing, -1, "File has not been opened in read mode."); - int to_copy = MIN(p_length, data.size() - pos); - for (int i = 0; i < to_copy; i++) { + uint64_t to_copy = MIN(p_length, get_length() - pos); + for (uint64_t i = 0; i < to_copy; i++) { p_dst[i] = data[pos++]; } @@ -256,16 +255,17 @@ Error FileAccessEncrypted::get_error() const { return eofed ? ERR_FILE_EOF : OK; } -void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) { +void FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); + ERR_FAIL_COND(!p_src && p_length > 0); - if (pos < data.size()) { - for (int i = 0; i < p_length; i++) { + if (pos < get_length()) { + for (uint64_t i = 0; i < p_length; i++) { store_8(p_src[i]); } - } else if (pos == data.size()) { + } else if (pos == get_length()) { data.resize(pos + p_length); - for (int i = 0; i < p_length; i++) { + for (uint64_t i = 0; i < p_length; i++) { data.write[pos + i] = p_src[i]; } pos += p_length; @@ -281,10 +281,10 @@ void FileAccessEncrypted::flush() { void FileAccessEncrypted::store_8(uint8_t p_dest) { ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); - if (pos < data.size()) { + if (pos < get_length()) { data.write[pos] = p_dest; pos++; - } else if (pos == data.size()) { + } else if (pos == get_length()) { data.push_back(p_dest); pos++; } diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 969052d04f..decffae696 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_ENCRYPTED_H #define FILE_ACCESS_ENCRYPTED_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #define ENCRYPTED_HEADER_MAGIC 0x43454447 @@ -47,10 +47,10 @@ private: Vector<uint8_t> key; bool writing = false; FileAccess *file = nullptr; - size_t base = 0; - size_t length = 0; + uint64_t base = 0; + uint64_t length = 0; Vector<uint8_t> data; - mutable int pos = 0; + mutable uint64_t pos = 0; mutable bool eofed = false; bool use_magic = true; @@ -68,21 +68,21 @@ public: virtual String get_path() const; /// returns the path for the current open file virtual String get_path_absolute() const; /// returns the absolute path for the current open file - virtual void seek(size_t p_position); ///< seek to a given position + virtual void seek(uint64_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual uint64_t get_position() const; ///< get position in the file + virtual uint64_t get_length() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; virtual Error get_error() const; ///< get last error virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte - virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes virtual bool file_exists(const String &p_name); ///< return true if a file exists diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index af155a77a8..627fd2bf9c 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -31,7 +31,7 @@ #include "file_access_memory.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/templates/map.h" static Map<String, Vector<uint8_t>> *files = nullptr; @@ -71,7 +71,7 @@ bool FileAccessMemory::file_exists(const String &p_name) { return files && (files->find(name) != nullptr); } -Error FileAccessMemory::open_custom(const uint8_t *p_data, int p_len) { +Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) { data = (uint8_t *)p_data; length = p_len; pos = 0; @@ -102,7 +102,7 @@ bool FileAccessMemory::is_open() const { return data != nullptr; } -void FileAccessMemory::seek(size_t p_position) { +void FileAccessMemory::seek(uint64_t p_position) { ERR_FAIL_COND(!data); pos = p_position; } @@ -112,12 +112,12 @@ void FileAccessMemory::seek_end(int64_t p_position) { pos = length + p_position; } -size_t FileAccessMemory::get_position() const { +uint64_t FileAccessMemory::get_position() const { ERR_FAIL_COND_V(!data, 0); return pos; } -size_t FileAccessMemory::get_len() const { +uint64_t FileAccessMemory::get_length() const { ERR_FAIL_COND_V(!data, 0); return length; } @@ -136,13 +136,12 @@ uint8_t FileAccessMemory::get_8() const { return ret; } -int FileAccessMemory::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); ERR_FAIL_COND_V(!data, -1); - int left = length - pos; - int read = MIN(p_length, left); + uint64_t left = length - pos; + uint64_t read = MIN(p_length, left); if (read < p_length) { WARN_PRINT("Reading less data than requested"); @@ -168,9 +167,10 @@ void FileAccessMemory::store_8(uint8_t p_byte) { data[pos++] = p_byte; } -void FileAccessMemory::store_buffer(const uint8_t *p_src, int p_length) { - int left = length - pos; - int write = MIN(p_length, left); +void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); + uint64_t left = length - pos; + uint64_t write = MIN(p_length, left); if (write < p_length) { WARN_PRINT("Writing less data than requested"); } diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 0e3b0ad7b1..14135bd68c 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -31,12 +31,12 @@ #ifndef FILE_ACCESS_MEMORY_H #define FILE_ACCESS_MEMORY_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" class FileAccessMemory : public FileAccess { uint8_t *data = nullptr; - int length = 0; - mutable int pos = 0; + uint64_t length = 0; + mutable uint64_t pos = 0; static FileAccess *create(); @@ -44,27 +44,27 @@ public: static void register_file(String p_name, Vector<uint8_t> p_data); static void cleanup(); - virtual Error open_custom(const uint8_t *p_data, int p_len); ///< open a file + 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); ///< open a file virtual void close(); ///< close a file virtual bool is_open() const; ///< true when file is open - virtual void seek(size_t p_position); ///< seek to a given position + virtual void seek(uint64_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual uint64_t get_position() const; ///< get position in the file + virtual uint64_t get_length() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; ///< get an array of bytes + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes virtual Error get_error() const; ///< get last error virtual void flush(); virtual void store_8(uint8_t p_byte); ///< store a byte - virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes virtual bool file_exists(const String &p_name); ///< return true if a file exists diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 4cc73bcd22..63a8f9c5b6 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -126,7 +126,7 @@ void FileAccessNetworkClient::_thread_func() { if (status != OK) { fa->_respond(0, Error(status)); } else { - uint64_t len = get_64(); + int64_t len = get_64(); fa->_respond(len, Error(status)); } @@ -135,7 +135,7 @@ void FileAccessNetworkClient::_thread_func() { } break; case FileAccessNetwork::RESPONSE_DATA: { int64_t offset = get_64(); - uint32_t len = get_32(); + int32_t len = get_32(); Vector<uint8_t> block; block.resize(len); @@ -219,13 +219,13 @@ FileAccessNetworkClient::~FileAccessNetworkClient() { thread.wait_to_finish(); } -void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) { - int page = p_offset / page_size; +void FileAccessNetwork::_set_block(uint64_t p_offset, const Vector<uint8_t> &p_block) { + int32_t page = p_offset / page_size; ERR_FAIL_INDEX(page, pages.size()); if (page < pages.size() - 1) { ERR_FAIL_COND(p_block.size() != page_size); } else { - ERR_FAIL_COND((p_block.size() != (int)(total_size % page_size))); + ERR_FAIL_COND((uint64_t)p_block.size() != total_size % page_size); } { @@ -240,7 +240,7 @@ void FileAccessNetwork::_set_block(int p_offset, const Vector<uint8_t> &p_block) } } -void FileAccessNetwork::_respond(size_t p_len, Error p_status) { +void FileAccessNetwork::_respond(uint64_t p_len, Error p_status) { DEBUG_PRINT("GOT RESPONSE - len: " + itos(p_len) + " status: " + itos(p_status)); response = p_status; if (response != OK) { @@ -248,7 +248,7 @@ void FileAccessNetwork::_respond(size_t p_len, Error p_status) { } opened = true; total_size = p_len; - int pc = ((total_size - 1) / page_size) + 1; + int32_t pc = ((total_size - 1) / page_size) + 1; pages.resize(pc); } @@ -307,8 +307,9 @@ bool FileAccessNetwork::is_open() const { return opened; } -void FileAccessNetwork::seek(size_t p_position) { +void FileAccessNetwork::seek(uint64_t p_position) { ERR_FAIL_COND_MSG(!opened, "File must be opened before use."); + eof_flag = p_position > total_size; if (p_position >= total_size) { @@ -322,12 +323,12 @@ void FileAccessNetwork::seek_end(int64_t p_position) { seek(total_size + p_position); } -size_t FileAccessNetwork::get_position() const { +uint64_t FileAccessNetwork::get_position() const { ERR_FAIL_COND_V_MSG(!opened, 0, "File must be opened before use."); return pos; } -size_t FileAccessNetwork::get_len() const { +uint64_t FileAccessNetwork::get_length() const { ERR_FAIL_COND_V_MSG(!opened, 0, "File must be opened before use."); return total_size; } @@ -343,7 +344,7 @@ uint8_t FileAccessNetwork::get_8() const { return v; } -void FileAccessNetwork::_queue_page(int p_page) const { +void FileAccessNetwork::_queue_page(int32_t p_page) const { if (p_page >= pages.size()) { return; } @@ -354,7 +355,7 @@ void FileAccessNetwork::_queue_page(int p_page) const { FileAccessNetworkClient::BlockRequest br; br.id = id; - br.offset = size_t(p_page) * page_size; + br.offset = (uint64_t)p_page * page_size; br.size = page_size; nc->block_requests.push_back(br); pages.write[p_page].queued = true; @@ -365,11 +366,9 @@ void FileAccessNetwork::_queue_page(int p_page) const { } } -int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccessNetwork::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); - //bool eof=false; if (pos + p_length > total_size) { eof_flag = true; } @@ -377,18 +376,16 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const { p_length = total_size - pos; } - //FileAccessNetworkClient *nc = FileAccessNetworkClient::singleton; - uint8_t *buff = last_page_buff; - for (int i = 0; i < p_length; i++) { - int page = pos / page_size; + for (uint64_t i = 0; i < p_length; i++) { + int32_t page = pos / page_size; if (page != last_page) { buffer_mutex.lock(); if (pages[page].buffer.is_empty()) { waiting_on_page = page; - for (int j = 0; j < read_ahead; j++) { + for (int32_t j = 0; j < read_ahead; j++) { _queue_page(page + j); } buffer_mutex.unlock(); @@ -396,10 +393,9 @@ int FileAccessNetwork::get_buffer(uint8_t *p_dst, int p_length) const { page_sem.wait(); DEBUG_PRINT("done"); } else { - for (int j = 0; j < read_ahead; j++) { + for (int32_t j = 0; j < read_ahead; j++) { _queue_page(page + j); } - //queue pages buffer_mutex.unlock(); } diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 1f5de3e5dd..1d9d761fbb 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_NETWORK_H #define FILE_ACCESS_NETWORK_H +#include "core/io/file_access.h" #include "core/io/stream_peer_tcp.h" -#include "core/os/file_access.h" #include "core/os/semaphore.h" #include "core/os/thread.h" @@ -40,9 +40,9 @@ class FileAccessNetwork; class FileAccessNetworkClient { struct BlockRequest { - int id; + int32_t id; uint64_t offset; - int size; + int32_t size; }; List<BlockRequest> block_requests; @@ -54,17 +54,17 @@ class FileAccessNetworkClient { Mutex blockrequest_mutex; Map<int, FileAccessNetwork *> accesses; Ref<StreamPeerTCP> client; - int last_id = 0; - int lockcount = 0; + int32_t last_id = 0; + int32_t lockcount = 0; Vector<uint8_t> block; void _thread_func(); static void _thread_func(void *s); - void put_32(int p_32); + void put_32(int32_t p_32); void put_64(int64_t p_64); - int get_32(); + int32_t get_32(); int64_t get_64(); void lock_mutex(); void unlock_mutex(); @@ -86,15 +86,15 @@ class FileAccessNetwork : public FileAccess { Semaphore page_sem; Mutex buffer_mutex; bool opened = false; - size_t total_size; - mutable size_t pos = 0; - int id; + uint64_t total_size; + mutable uint64_t pos = 0; + int32_t id; mutable bool eof_flag = false; - mutable int last_page = -1; + mutable int32_t last_page = -1; mutable uint8_t *last_page_buff = nullptr; - int page_size; - int read_ahead; + int32_t page_size; + int32_t read_ahead; mutable int waiting_on_page = -1; @@ -110,9 +110,9 @@ class FileAccessNetwork : public FileAccess { uint64_t exists_modtime; friend class FileAccessNetworkClient; - void _queue_page(int p_page) const; - void _respond(size_t p_len, Error p_status); - void _set_block(int p_offset, const Vector<uint8_t> &p_block); + void _queue_page(int32_t p_page) const; + void _respond(uint64_t p_len, Error p_status); + void _set_block(uint64_t p_offset, const Vector<uint8_t> &p_block); public: enum Command { @@ -134,15 +134,15 @@ public: virtual void close(); ///< close a file virtual bool is_open() const; ///< true when file is open - virtual void seek(size_t p_position); ///< seek to a given position + virtual void seek(uint64_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual uint64_t get_position() const; ///< get position in the file + virtual uint64_t get_length() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; virtual Error get_error() const; ///< get last error diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index e24dc40166..7b43daf9c0 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -36,7 +36,7 @@ #include <stdio.h> -Error PackedData::add_pack(const String &p_path, bool p_replace_files, size_t p_offset) { +Error PackedData::add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) { for (int i = 0; i < sources.size(); i++) { if (sources[i]->try_open_pack(p_path, p_replace_files, p_offset)) { return OK; @@ -46,17 +46,16 @@ Error PackedData::add_pack(const String &p_path, bool p_replace_files, size_t p_ return ERR_FILE_UNRECOGNIZED; } -void PackedData::add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) { - PathMD5 pmd5(path.md5_buffer()); - //printf("adding path %s, %lli, %lli\n", path.utf8().get_data(), pmd5.a, pmd5.b); +void PackedData::add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted) { + PathMD5 pmd5(p_path.md5_buffer()); bool exists = files.has(pmd5); PackedFile pf; pf.encrypted = p_encrypted; - pf.pack = pkg_path; - pf.offset = ofs; - pf.size = size; + pf.pack = p_pkg_path; + pf.offset = p_ofs; + pf.size = p_size; for (int i = 0; i < 16; i++) { pf.md5[i] = p_md5[i]; } @@ -68,7 +67,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o if (!exists) { //search for dir - String p = path.replace_first("res://", ""); + String p = p_path.replace_first("res://", ""); PackedDir *cd = root; if (p.find("/") != -1) { //in a subdir @@ -87,7 +86,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o } } } - String filename = path.get_file(); + String filename = p_path.get_file(); // Don't add as a file if the path points to a directory if (!filename.is_empty()) { cd->files.insert(filename); @@ -126,7 +125,7 @@ PackedData::~PackedData() { ////////////////////////////////////////////////////////////////// -bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) { +bool PackedSourcePCK::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) { FileAccess *f = FileAccess::open(p_path, FileAccess::READ); if (!f) { return false; @@ -261,7 +260,7 @@ bool FileAccessPack::is_open() const { return f->is_open(); } -void FileAccessPack::seek(size_t p_position) { +void FileAccessPack::seek(uint64_t p_position) { if (p_position > pf.size) { eof = true; } else { @@ -276,11 +275,11 @@ void FileAccessPack::seek_end(int64_t p_position) { seek(pf.size + p_position); } -size_t FileAccessPack::get_position() const { +uint64_t FileAccessPack::get_position() const { return pos; } -size_t FileAccessPack::get_len() const { +uint64_t FileAccessPack::get_length() const { return pf.size; } @@ -298,18 +297,17 @@ uint8_t FileAccessPack::get_8() const { return f->get_8(); } -int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccessPack::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); if (eof) { return 0; } - uint64_t to_read = p_length; + int64_t to_read = p_length; if (to_read + pos > pf.size) { eof = true; - to_read = int64_t(pf.size) - int64_t(pos); + to_read = (int64_t)pf.size - (int64_t)pos; } pos += p_length; @@ -322,9 +320,9 @@ int FileAccessPack::get_buffer(uint8_t *p_dst, int p_length) const { return to_read; } -void FileAccessPack::set_endian_swap(bool p_swap) { - FileAccess::set_endian_swap(p_swap); - f->set_endian_swap(p_swap); +void FileAccessPack::set_big_endian(bool p_big_endian) { + FileAccess::set_big_endian(p_big_endian); + f->set_big_endian(p_big_endian); } Error FileAccessPack::get_error() const { @@ -342,7 +340,7 @@ void FileAccessPack::store_8(uint8_t p_dest) { ERR_FAIL(); } -void FileAccessPack::store_buffer(const uint8_t *p_src, int p_length) { +void FileAccessPack::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL(); } @@ -549,7 +547,7 @@ Error DirAccessPack::remove(String p_name) { return ERR_UNAVAILABLE; } -size_t DirAccessPack::get_space_left() { +uint64_t DirAccessPack::get_space_left() { return 0; } diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 955108f455..2f0ee62723 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_PACK_H #define FILE_ACCESS_PACK_H -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/string/print_string.h" #include "core/templates/list.h" #include "core/templates/map.h" @@ -112,13 +112,13 @@ private: public: void add_pack_source(PackSource *p_source); - void add_path(const String &pkg_path, const String &path, uint64_t ofs, uint64_t size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource + void add_path(const String &p_pkg_path, const String &p_path, uint64_t p_ofs, uint64_t p_size, const uint8_t *p_md5, PackSource *p_src, bool p_replace_files, bool p_encrypted = false); // for PackSource void set_disabled(bool p_disabled) { disabled = p_disabled; } _FORCE_INLINE_ bool is_disabled() const { return disabled; } static PackedData *get_singleton() { return singleton; } - Error add_pack(const String &p_path, bool p_replace_files, size_t p_offset); + Error add_pack(const String &p_path, bool p_replace_files, uint64_t p_offset); _FORCE_INLINE_ FileAccess *try_open_path(const String &p_path); _FORCE_INLINE_ bool has_path(const String &p_path); @@ -132,21 +132,21 @@ public: class PackSource { public: - virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset) = 0; + virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset) = 0; virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file) = 0; virtual ~PackSource() {} }; class PackedSourcePCK : public PackSource { public: - virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset); + virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset); virtual FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file); }; class FileAccessPack : public FileAccess { PackedData::PackedFile pf; - mutable size_t pos; + mutable uint64_t pos; mutable bool eof; uint64_t off; @@ -160,25 +160,25 @@ public: virtual void close(); virtual bool is_open() const; - virtual void seek(size_t p_position); + virtual void seek(uint64_t p_position); virtual void seek_end(int64_t p_position = 0); - virtual size_t get_position() const; - virtual size_t get_len() const; + virtual uint64_t get_position() const; + virtual uint64_t get_length() const; virtual bool eof_reached() const; virtual uint8_t get_8() const; - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; - virtual void set_endian_swap(bool p_swap); + virtual void set_big_endian(bool p_big_endian); virtual Error get_error() const; virtual void flush(); virtual void store_8(uint8_t p_dest); - virtual void store_buffer(const uint8_t *p_src, int p_length); + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); virtual bool file_exists(const String &p_name); @@ -243,7 +243,11 @@ public: virtual Error rename(String p_from, String p_to); virtual Error remove(String p_name); - size_t get_space_left(); + uint64_t get_space_left(); + + virtual bool is_link(String p_file) { return false; } + virtual String read_link(String p_file) { return p_file; } + virtual Error create_link(String p_source, String p_target) { return FAILED; } virtual String get_filesystem_type() const; diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index dbedb5254f..b5c882e9ce 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -32,7 +32,7 @@ #include "file_access_zip.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" ZipArchive *ZipArchive::instance = nullptr; @@ -67,13 +67,13 @@ static long godot_tell(voidpf opaque, voidpf stream) { static long godot_seek(voidpf opaque, voidpf stream, uLong offset, int origin) { FileAccess *f = (FileAccess *)stream; - int pos = offset; + uint64_t pos = offset; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: pos = f->get_position() + offset; break; case ZLIB_FILEFUNC_SEEK_END: - pos = f->get_len() + offset; + pos = f->get_length() + offset; break; default: break; @@ -144,8 +144,7 @@ unzFile ZipArchive::get_file_handle(String p_file) const { return pkg; } -bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset = 0) { - //printf("opening zip pack %s, %i, %i\n", p_name.utf8().get_data(), p_name.extension().nocasecmp_to("zip"), p_name.extension().nocasecmp_to("pcz")); +bool ZipArchive::try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset = 0) { // load with offset feature only supported for PCK files ERR_FAIL_COND_V_MSG(p_offset != 0, false, "Invalid PCK data. Note that loading files with a non-zero offset isn't supported with ZIP archives."); @@ -227,9 +226,7 @@ ZipArchive::ZipArchive() { ZipArchive::~ZipArchive() { for (int i = 0; i < packages.size(); i++) { - FileAccess *f = (FileAccess *)unzGetOpaque(packages[i].zfile); unzClose(packages[i].zfile); - memdelete(f); } packages.clear(); @@ -265,22 +262,23 @@ bool FileAccessZip::is_open() const { return zfile != nullptr; } -void FileAccessZip::seek(size_t p_position) { +void FileAccessZip::seek(uint64_t p_position) { ERR_FAIL_COND(!zfile); + unzSeekCurrentFile(zfile, p_position); } void FileAccessZip::seek_end(int64_t p_position) { ERR_FAIL_COND(!zfile); - unzSeekCurrentFile(zfile, get_len() + p_position); + unzSeekCurrentFile(zfile, get_length() + p_position); } -size_t FileAccessZip::get_position() const { +uint64_t FileAccessZip::get_position() const { ERR_FAIL_COND_V(!zfile, 0); return unztell(zfile); } -size_t FileAccessZip::get_len() const { +uint64_t FileAccessZip::get_length() const { ERR_FAIL_COND_V(!zfile, 0); return file_info.uncompressed_size; } @@ -297,17 +295,17 @@ uint8_t FileAccessZip::get_8() const { return ret; } -int FileAccessZip::get_buffer(uint8_t *p_dst, int p_length) const { +uint64_t FileAccessZip::get_buffer(uint8_t *p_dst, uint64_t p_length) const { ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); - ERR_FAIL_COND_V(p_length < 0, -1); ERR_FAIL_COND_V(!zfile, -1); + at_eof = unzeof(zfile); if (at_eof) { return 0; } - int read = unzReadCurrentFile(zfile, p_dst, p_length); + int64_t read = unzReadCurrentFile(zfile, p_dst, p_length); ERR_FAIL_COND_V(read < 0, read); - if (read < p_length) { + if ((uint64_t)read < p_length) { at_eof = true; } return read; diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index 8559f871ce..cca14ded62 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -67,7 +67,7 @@ public: bool file_exists(String p_name) const; - virtual bool try_open_pack(const String &p_path, bool p_replace_files, size_t p_offset); + virtual bool try_open_pack(const String &p_path, bool p_replace_files, uint64_t p_offset); FileAccess *get_file(const String &p_path, PackedData::PackedFile *p_file); static ZipArchive *get_singleton(); @@ -87,20 +87,21 @@ public: virtual void close(); ///< close a file virtual bool is_open() const; ///< true when file is open - virtual void seek(size_t p_position); ///< seek to a given position + virtual void seek(uint64_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_position() const; ///< get position in the file - virtual size_t get_len() const; ///< get size of the file + virtual uint64_t get_position() const; ///< get position in the file + virtual uint64_t get_length() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF virtual uint8_t get_8() const; ///< get a byte - virtual int get_buffer(uint8_t *p_dst, int p_length) const; + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; virtual Error get_error() const; ///< get last error virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte + virtual bool file_exists(const String &p_name); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo diff --git a/core/io/http_client.h b/core/io/http_client.h index ec4b86b26f..f70999836f 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -34,10 +34,10 @@ #include "core/io/ip.h" #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class HTTPClient : public Reference { - GDCLASS(HTTPClient, Reference); +class HTTPClient : public RefCounted { + GDCLASS(HTTPClient, RefCounted); public: enum ResponseCode { diff --git a/core/io/image.cpp b/core/io/image.cpp index c36fa6e45f..9cd0ea7b5d 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1428,16 +1428,23 @@ void Image::flip_x() { } } +/// Get mipmap size and offset. int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) { + // Data offset in mipmaps (including the original texture). int size = 0; + int w = p_width; int h = p_height; + + // Current mipmap index in the loop below. p_mipmaps is the target mipmap index. + // In this function, mipmap 0 represents the first mipmap instead of the original texture. int mm = 0; int pixsize = get_format_pixel_size(p_format); int pixshift = get_format_pixel_rshift(p_format); int block = get_format_block_size(p_format); - //technically, you can still compress up to 1 px no matter the format, so commenting this + + // Technically, you can still compress up to 1 px no matter the format, so commenting this. //int minw, minh; //get_format_min_pixel_size(p_format, minw, minh); int minw = 1, minh = 1; @@ -1453,17 +1460,6 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & size += s; - if (r_mm_width) { - *r_mm_width = bw; - } - if (r_mm_height) { - *r_mm_height = bh; - } - - if (p_mipmaps >= 0 && mm == p_mipmaps) { - break; - } - if (p_mipmaps >= 0) { w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); @@ -1474,6 +1470,21 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); } + + // Set mipmap size. + // It might be necessary to put this after the minimum mipmap size check because of the possible occurrence of "1 >> 1". + if (r_mm_width) { + *r_mm_width = bw >> 1; + } + if (r_mm_height) { + *r_mm_height = bh >> 1; + } + + // Reach target mipmap. + if (p_mipmaps >= 0 && mm == p_mipmaps) { + break; + } + mm++; } @@ -2718,10 +2729,11 @@ void (*Image::_image_decompress_bptc)(Image *) = nullptr; void (*Image::_image_decompress_etc1)(Image *) = nullptr; void (*Image::_image_decompress_etc2)(Image *) = nullptr; -Vector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = nullptr; -Ref<Image> (*Image::lossy_unpacker)(const Vector<uint8_t> &) = nullptr; -Vector<uint8_t> (*Image::lossless_packer)(const Ref<Image> &) = nullptr; -Ref<Image> (*Image::lossless_unpacker)(const Vector<uint8_t> &) = nullptr; +Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr; +Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr; +Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr; +Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr; +Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr; Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr; Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr; diff --git a/core/io/image.h b/core/io/image.h index df8f9b35a1..060e54a308 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -148,10 +148,11 @@ public: static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc2)(Image *); - static Vector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality); - static Ref<Image> (*lossy_unpacker)(const Vector<uint8_t> &p_buffer); - static Vector<uint8_t> (*lossless_packer)(const Ref<Image> &p_image); - static Ref<Image> (*lossless_unpacker)(const Vector<uint8_t> &p_buffer); + static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality); + static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image); + static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer); + static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image); + static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer); static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels); static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer); diff --git a/core/io/image_loader.h b/core/io/image_loader.h index a5d588e0b5..6d1b1e3646 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -31,9 +31,9 @@ #ifndef IMAGE_LOADER_H #define IMAGE_LOADER_H +#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/string/ustring.h" #include "core/templates/list.h" diff --git a/core/io/ip.cpp b/core/io/ip.cpp index eb7814054b..001b1c4757 100644 --- a/core/io/ip.cpp +++ b/core/io/ip.cpp @@ -41,13 +41,15 @@ VARIANT_ENUM_CAST(IP::ResolverStatus); struct _IP_ResolverPrivate { struct QueueItem { SafeNumeric<IP::ResolverStatus> status; - IPAddress response; + + List<IPAddress> response; + String hostname; IP::Type type; void clear() { status.set(IP::RESOLVER_STATUS_NONE); - response = IPAddress(); + response.clear(); type = IP::TYPE_NONE; hostname = ""; }; @@ -80,13 +82,9 @@ struct _IP_ResolverPrivate { if (queue[i].status.get() != IP::RESOLVER_STATUS_WAITING) { continue; } - queue[i].response = IP::get_singleton()->resolve_hostname(queue[i].hostname, queue[i].type); - if (!queue[i].response.is_valid()) { - queue[i].status.set(IP::RESOLVER_STATUS_ERROR); - } else { - queue[i].status.set(IP::RESOLVER_STATUS_DONE); - } + IP::get_singleton()->_resolve_hostname(queue[i].response, queue[i].hostname, queue[i].type); + queue[i].status.set(queue[i].response.is_empty() ? IP::RESOLVER_STATUS_ERROR : IP::RESOLVER_STATUS_DONE); } } @@ -101,7 +99,7 @@ struct _IP_ResolverPrivate { } } - HashMap<String, IPAddress> cache; + HashMap<String, List<IPAddress>> cache; static String get_cache_key(String p_hostname, IP::Type p_type) { return itos(p_type) + p_hostname; @@ -111,15 +109,41 @@ struct _IP_ResolverPrivate { IPAddress IP::resolve_hostname(const String &p_hostname, IP::Type p_type) { MutexLock lock(resolver->mutex); + List<IPAddress> res; + String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); - if (resolver->cache.has(key) && resolver->cache[key].is_valid()) { - IPAddress res = resolver->cache[key]; - return res; + if (resolver->cache.has(key)) { + res = resolver->cache[key]; + } else { + _resolve_hostname(res, p_hostname, p_type); + resolver->cache[key] = res; } - IPAddress res = _resolve_hostname(p_hostname, p_type); - resolver->cache[key] = res; - return res; + for (int i = 0; i < res.size(); ++i) { + if (res[i].is_valid()) { + return res[i]; + } + } + return IPAddress(); +} + +Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) { + MutexLock lock(resolver->mutex); + + String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); + if (!resolver->cache.has(key)) { + _resolve_hostname(resolver->cache[key], p_hostname, p_type); + } + + List<IPAddress> res = resolver->cache[key]; + + Array result; + for (int i = 0; i < res.size(); ++i) { + if (res[i].is_valid()) { + result.push_back(String(res[i])); + } + } + return result; } IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Type p_type) { @@ -135,11 +159,11 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type); resolver->queue[id].hostname = p_hostname; resolver->queue[id].type = p_type; - if (resolver->cache.has(key) && resolver->cache[key].is_valid()) { + if (resolver->cache.has(key)) { resolver->queue[id].response = resolver->cache[key]; resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE); } else { - resolver->queue[id].response = IPAddress(); + resolver->queue[id].response = List<IPAddress>(); resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING); if (resolver->thread.is_started()) { resolver->sem.post(); @@ -158,7 +182,6 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const { if (resolver->queue[p_id].status.get() == IP::RESOLVER_STATUS_NONE) { ERR_PRINT("Condition status == IP::RESOLVER_STATUS_NONE"); - resolver->mutex.unlock(); return IP::RESOLVER_STATUS_NONE; } return resolver->queue[p_id].status.get(); @@ -171,11 +194,37 @@ IPAddress IP::get_resolve_item_address(ResolverID p_id) const { if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) { ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet."); - resolver->mutex.unlock(); return IPAddress(); } - return resolver->queue[p_id].response; + List<IPAddress> res = resolver->queue[p_id].response; + + for (int i = 0; i < res.size(); ++i) { + if (res[i].is_valid()) { + return res[i]; + } + } + return IPAddress(); +} + +Array IP::get_resolve_item_addresses(ResolverID p_id) const { + ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, Array()); + MutexLock lock(resolver->mutex); + + if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) { + ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet."); + return Array(); + } + + List<IPAddress> res = resolver->queue[p_id].response; + + Array result; + for (int i = 0; i < res.size(); ++i) { + if (res[i].is_valid()) { + result.push_back(String(res[i])); + } + } + return result; } void IP::erase_resolve_item(ResolverID p_id) { @@ -245,9 +294,11 @@ void IP::get_local_addresses(List<IPAddress> *r_addresses) const { void IP::_bind_methods() { ClassDB::bind_method(D_METHOD("resolve_hostname", "host", "ip_type"), &IP::resolve_hostname, DEFVAL(IP::TYPE_ANY)); + ClassDB::bind_method(D_METHOD("resolve_hostname_addresses", "host", "ip_type"), &IP::resolve_hostname_addresses, DEFVAL(IP::TYPE_ANY)); ClassDB::bind_method(D_METHOD("resolve_hostname_queue_item", "host", "ip_type"), &IP::resolve_hostname_queue_item, DEFVAL(IP::TYPE_ANY)); ClassDB::bind_method(D_METHOD("get_resolve_item_status", "id"), &IP::get_resolve_item_status); ClassDB::bind_method(D_METHOD("get_resolve_item_address", "id"), &IP::get_resolve_item_address); + ClassDB::bind_method(D_METHOD("get_resolve_item_addresses", "id"), &IP::get_resolve_item_addresses); ClassDB::bind_method(D_METHOD("erase_resolve_item", "id"), &IP::erase_resolve_item); ClassDB::bind_method(D_METHOD("get_local_addresses"), &IP::_get_local_addresses); ClassDB::bind_method(D_METHOD("get_local_interfaces"), &IP::_get_local_interfaces); diff --git a/core/io/ip.h b/core/io/ip.h index 0c4a83257d..3c6040a1f0 100644 --- a/core/io/ip.h +++ b/core/io/ip.h @@ -69,7 +69,6 @@ protected: static IP *singleton; static void _bind_methods(); - virtual IPAddress _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0; Array _get_local_addresses() const; Array _get_local_interfaces() const; @@ -84,11 +83,16 @@ public: }; IPAddress resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY); + Array resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY); // async resolver hostname ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY); ResolverStatus get_resolve_item_status(ResolverID p_id) const; IPAddress get_resolve_item_address(ResolverID p_id) const; virtual void get_local_addresses(List<IPAddress> *r_addresses) const; + + virtual void _resolve_hostname(List<IPAddress> &r_addresses, const String &p_hostname, Type p_type = TYPE_ANY) const = 0; + Array get_resolve_item_addresses(ResolverID p_id) const; + virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const = 0; void erase_resolve_item(ResolverID p_id); diff --git a/core/io/json.cpp b/core/io/json.cpp index 394cf216e8..82ef2a6894 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -55,7 +55,7 @@ static String _make_indent(const String &p_indent, int p_size) { return indent_text; } -String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys) { +String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) { String colon = ":"; String end_statement = ""; @@ -71,8 +71,17 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ return p_var.operator bool() ? "true" : "false"; case Variant::INT: return itos(p_var); - case Variant::FLOAT: - return rtos(p_var); + case Variant::FLOAT: { + double num = p_var; + if (p_full_precision) { + // Store unreliable digits (17) instead of just reliable + // digits (14) so that the value can be decoded exactly. + return String::num(num, 17 - (int)floor(log10(num))); + } else { + // Store only reliable digits (14) by default. + return String::num(num, 14 - (int)floor(log10(num))); + } + } case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: case Variant::PACKED_FLOAT32_ARRAY: @@ -82,20 +91,29 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ String s = "["; s += end_statement; Array a = p_var; + + ERR_FAIL_COND_V_MSG(p_markers.has(a.id()), "\"[...]\"", "Converting circular structure to JSON."); + p_markers.insert(a.id()); + for (int i = 0; i < a.size(); i++) { if (i > 0) { s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys); + s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "]"; + p_markers.erase(a.id()); return s; } case Variant::DICTIONARY: { String s = "{"; s += end_statement; Dictionary d = p_var; + + ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON."); + p_markers.insert(d.id()); + List<Variant> keys; d.get_key_list(&keys); @@ -108,12 +126,13 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys); + s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers); s += colon; - s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys); + s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "}"; + p_markers.erase(d.id()); return s; } default: @@ -121,8 +140,9 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ } } -String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys) { - return _print_var(p_var, p_indent, 0, p_sort_keys); +String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { + Set<const void *> markers; + return _print_var(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); } Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) { diff --git a/core/io/json.h b/core/io/json.h index 537477666e..5be8cc1e86 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -31,7 +31,7 @@ #ifndef JSON_H #define JSON_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/variant/variant.h" class JSON { enum TokenType { @@ -62,7 +62,7 @@ class JSON { static const char *tk_name[TK_MAX]; - static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys); + static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<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); @@ -70,12 +70,12 @@ class JSON { static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); public: - static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true); + static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); }; -class JSONParser : public Reference { - GDCLASS(JSONParser, Reference); +class JSONParser : public RefCounted { + GDCLASS(JSONParser, RefCounted); Variant data; String string; diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 8a07459a1d..09539f716c 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -31,8 +31,9 @@ #include "logger.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/string/print_string.h" #if defined(MINGW_ENABLED) || defined(_MSC_VER) @@ -156,11 +157,7 @@ void RotatedFileLogger::rotate_file() { if (FileAccess::exists(base_path)) { if (max_files > 1) { - char timestamp[21]; - OS::Date date = OS::get_singleton()->get_date(); - OS::Time time = OS::get_singleton()->get_time(); - sprintf(timestamp, "_%04d-%02d-%02d_%02d.%02d.%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); - + String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", "."); String backup_name = base_path.get_basename() + timestamp; if (base_path.get_extension() != String()) { backup_name += "." + base_path.get_extension(); diff --git a/core/io/logger.h b/core/io/logger.h index a12945911c..ccf68562d6 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -31,7 +31,7 @@ #ifndef LOGGER_H #define LOGGER_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/ustring.h" #include "core/templates/vector.h" diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 0282609270..4c58c84c14 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -30,7 +30,7 @@ #include "marshalls.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" @@ -279,9 +279,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } break; - case Variant::QUAT: { + case Variant::QUATERNION: { ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); - Quat val; + Quaternion val; val.x = decode_float(&buf[0]); val.y = decode_float(&buf[4]); val.z = decode_float(&buf[8]); @@ -325,9 +325,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { ERR_FAIL_COND_V(len < 4 * 12, ERR_INVALID_DATA); - Transform val; + Transform3D val; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * 4]); @@ -489,8 +489,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int obj->set(str, value); } - if (Object::cast_to<Reference>(obj)) { - REF ref = REF(Object::cast_to<Reference>(obj)); + if (Object::cast_to<RefCounted>(obj)) { + REF ref = REF(Object::cast_to<RefCounted>(obj)); r_variant = ref; } else { r_variant = obj; @@ -889,7 +889,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo // Test for potential wrong values sent by the debugger when it breaks. Object *obj = p_variant.get_validated_object(); if (!obj) { - // Object is invalid, send a nullptr instead. + // Object is invalid, send a nullptr instead. if (buf) { encode_uint32(Variant::NIL, buf); } @@ -1099,9 +1099,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 4 * 4; } break; - case Variant::QUAT: { + case Variant::QUATERNION: { if (buf) { - Quat q = p_variant; + Quaternion q = p_variant; encode_float(q.x, &buf[0]); encode_float(q.y, &buf[4]); encode_float(q.z, &buf[8]); @@ -1138,9 +1138,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 9 * 4; } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { if (buf) { - Transform val = p_variant; + Transform3D val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { memcpy(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float)); diff --git a/core/io/marshalls.h b/core/io/marshalls.h index cc0e9ba301..7fac708f97 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -31,7 +31,7 @@ #ifndef MARSHALLS_H #define MARSHALLS_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/typedefs.h" #include "core/variant/variant.h" @@ -165,8 +165,8 @@ static inline double decode_double(const uint8_t *p_arr) { return md.d; } -class EncodedObjectAsID : public Reference { - GDCLASS(EncodedObjectAsID, Reference); +class EncodedObjectAsID : public RefCounted { + GDCLASS(EncodedObjectAsID, RefCounted); ObjectID id; diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 8414ee7c0c..78ec7ea21a 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -44,6 +44,56 @@ #include "core/os/os.h" #endif +String _get_rpc_md5(const Node *p_node) { + String rpc_list; + const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + rpc_list += String(node_config[i].name); + } + if (p_node->get_script_instance()) { + const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + rpc_list += String(script_config[i].name); + } + } + return rpc_list.md5_text(); +} + +const MultiplayerAPI::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) { + const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + if (node_config[i].name == p_method) { + r_id = ((uint16_t)i) & (1 << 15); + return node_config[i]; + } + } + if (p_node->get_script_instance()) { + const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + if (script_config[i].name == p_method) { + r_id = (uint16_t)i; + return script_config[i]; + } + } + } + return MultiplayerAPI::RPCConfig(); +} + +const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) { + Vector<MultiplayerAPI::RPCConfig> config; + uint16_t id = p_id; + if (id & (1 << 15)) { + id = id & ~(1 << 15); + config = p_node->get_node_rpc_methods(); + } else { + config = p_node->get_script_instance()->get_rpc_methods(); + } + if (id < config.size()) { + return config[p_id]; + } + return MultiplayerAPI::RPCConfig(); +} + _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) { switch (mode) { case MultiplayerAPI::RPC_MODE_DISABLED: { @@ -231,8 +281,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ _process_confirm_path(p_from, p_packet, p_packet_len); } break; - case NETWORK_COMMAND_REMOTE_CALL: - case NETWORK_COMMAND_REMOTE_SET: { + case NETWORK_COMMAND_REMOTE_CALL: { // Extract packet meta int packet_min_size = 1; int name_id_offset = 1; @@ -302,13 +351,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } const int packet_len = get_packet_len(node_target, p_packet_len); - if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { - _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); - - } else { - _process_rset(node, name_id, p_from, p_packet, packet_len, packet_min_size); - } - + _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); } break; case NETWORK_COMMAND_RAW: { @@ -362,16 +405,11 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small."); // Check that remote can call the RPC on this node. - StringName name = p_node->get_node_rpc_method(p_rpc_method_id); - RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id); - if (name == StringName() && p_node->get_script_instance()) { - name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id); - rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id); - } - ERR_FAIL_COND(name == StringName()); + const RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id); + ERR_FAIL_COND(config.name == StringName()); - bool can_call = _can_call_mode(p_node, rpc_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); + bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from); + ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); int argc = 0; bool byte_only = false; @@ -424,47 +462,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, Callable::CallError ce; - p_node->call(name, (const Variant **)argp.ptr(), argc, ce); + p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); if (ce.error != Callable::CallError::CALL_OK) { - String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce); + String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); error = "RPC - " + error; ERR_PRINT(error); } } -void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); - - // Check that remote can call the RSET on this node. - StringName name = p_node->get_node_rset_property(p_rpc_property_id); - RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id); - if (name == StringName() && p_node->get_script_instance()) { - name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id); - rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id); - } - ERR_FAIL_COND(name == StringName()); - - bool can_call = _can_call_mode(p_node, rset_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - -#ifdef DEBUG_ENABLED - _profile_node_data("in_rset", p_node->get_instance_id()); -#endif - - Variant value; - Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, nullptr); - - ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value."); - - bool valid; - - p_node->set(name, value, &valid); - if (!valid) { - String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + "."; - ERR_PRINT(error); - } -} - void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); int ofs = 1; @@ -487,7 +492,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, Node *node = root_node->get_node(path); ERR_FAIL_COND(node == nullptr); - const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5; + const bool valid_rpc_checksum = _get_rpc_md5(node) == methods_md5; if (valid_rpc_checksum == false) { ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); } @@ -569,7 +574,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC const int path_len = encode_cstring(path.get_data(), nullptr); // Extract MD5 from rpc methods list. - const String methods_md5 = p_node->get_rpc_md5(); + const String methods_md5 = _get_rpc_md5(p_node); const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. Vector<uint8_t> packet; @@ -752,7 +757,7 @@ Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const u return OK; } -void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { +void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree."); ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); @@ -797,7 +802,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p // - `NetworkNameIdCompression` in the next 1 bit. // - `byte_only_or_no_args` in the next 1 bit. // - So we still have the last bit free! - uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + uint8_t command_type = NETWORK_COMMAND_REMOTE_CALL; uint8_t node_id_compression = UINT8_MAX; uint8_t name_id_compression = UINT8_MAX; bool byte_only_or_no_args = false; @@ -837,81 +842,42 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p ofs += 4; } - if (p_set) { - // Take the rpc property ID - uint16_t property_id = p_from->get_node_rset_property_id(p_name); - if (property_id == UINT16_MAX && p_from->get_script_instance()) { - property_id = p_from->get_script_instance()->get_rset_property_id(p_name); - } - ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". this can happen only if this property is not marked as `remote`."); - - if (property_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(property_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(property_id, &(packet_cache.write[ofs])); - ofs += 2; - } - - // Set argument. - int len(0); - Error err = _encode_and_compress_variant(*p_arg[0], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - _encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len); - ofs += len; - + // Encode method ID + if (p_rpc_id <= UINT8_MAX) { + // The ID fits in 1 byte + name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id); + ofs += 1; } else { - // Take the rpc method ID - uint16_t method_id = p_from->get_node_rpc_method_id(p_name); - if (method_id == UINT16_MAX && p_from->get_script_instance()) { - method_id = p_from->get_script_instance()->get_rpc_method_id(p_name); - } - ERR_FAIL_COND_MSG(method_id == UINT16_MAX, - vformat("Unable to take the `method_id` for the function \"%s\" at path: \"%s\". This happens when the method is not marked as `remote`.", p_name, p_from->get_path())); - - if (method_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(method_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(method_id, &(packet_cache.write[ofs])); - ofs += 2; - } + // The ID is larger, let's use 2 bytes + name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(p_rpc_id, &(packet_cache.write[ofs])); + ofs += 2; + } - if (p_argcount == 0) { - byte_only_or_no_args = true; - } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { - byte_only_or_no_args = true; - // Special optimization when only the byte vector is sent. - const Vector<uint8_t> data = *p_arg[0]; - MAKE_ROOM(ofs + data.size()); - memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); - ofs += data.size(); - } else { - // Arguments - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = p_argcount; - ofs += 1; - for (int i = 0; i < p_argcount; i++) { - int len(0); - Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); - ofs += len; - } + if (p_argcount == 0) { + byte_only_or_no_args = true; + } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { + byte_only_or_no_args = true; + // Special optimization when only the byte vector is sent. + const Vector<uint8_t> data = *p_arg[0]; + MAKE_ROOM(ofs + data.size()); + memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); + ofs += data.size(); + } else { + // Arguments + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = p_argcount; + ofs += 1; + for (int i = 0; i < p_argcount; i++) { + int len(0); + Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); + MAKE_ROOM(ofs + len); + _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); + ofs += len; } } @@ -927,7 +893,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p #endif // Take chance and set transfer mode, since all send methods will use it. - network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(p_config.transfer_mode); if (has_all_peers) { // They all have verified paths, so send fast. @@ -1015,19 +981,15 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const bool call_local_native = false; bool call_local_script = false; bool is_master = p_node->is_network_master(); - + uint16_t rpc_id = UINT16_MAX; + const RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id); + ERR_FAIL_COND_MSG(config.name == StringName(), + vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path())); if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - // Check that send mode can use local call. - - RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method); - call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc); - - if (call_local_native) { - // Done below. - } else if (p_node->get_script_instance()) { - // Attempt with script. - rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); - call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc); + if (rpc_id & (1 << 15)) { + call_local_native = _should_call_local(config.rpc_mode, is_master, skip_rpc); + } else { + call_local_script = _should_call_local(config.rpc_mode, is_master, skip_rpc); } } @@ -1036,7 +998,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const _profile_node_data("out_rpc", p_node->get_instance_id()); #endif - _send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount); + _send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); } if (call_local_native) { @@ -1071,70 +1033,6 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode."); } -void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { - ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to RSET while no network peer is active."); - ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to RSET on a node which is not inside SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to send an RSET via a network peer which is not connected."); - - int node_id = network_peer->get_unique_id(); - bool is_master = p_node->is_network_master(); - bool skip_rset = node_id == p_peer_id; - bool set_local = false; - - if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - // Check that send mode can use local call. - RPCMode rpc_mode = p_node->get_node_rset_mode(p_property); - set_local = _should_call_local(rpc_mode, is_master, skip_rset); - - if (set_local) { - bool valid; - int temp_id = rpc_sender_id; - - rpc_sender_id = get_network_unique_id(); - p_node->set(p_property, p_value, &valid); - rpc_sender_id = temp_id; - - if (!valid) { - String error = "rset() aborted in local set, property not found: - " + String(p_property) + "."; - ERR_PRINT(error); - return; - } - } else if (p_node->get_script_instance()) { - // Attempt with script. - rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); - - set_local = _should_call_local(rpc_mode, is_master, skip_rset); - - if (set_local) { - int temp_id = rpc_sender_id; - - rpc_sender_id = get_network_unique_id(); - bool valid = p_node->get_script_instance()->set(p_property, p_value); - rpc_sender_id = temp_id; - - if (!valid) { - String error = "rset() aborted in local script set, property not found: - " + String(p_property) + "."; - ERR_PRINT(error); - return; - } - } - } - } - - if (skip_rset) { - ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode."); - return; - } - -#ifdef DEBUG_ENABLED - _profile_node_data("out_rset", p_node->get_instance_id()); -#endif - - const Variant *vptr = &p_value; - - _send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1); -} - Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet."); ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active."); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 7f88b53a27..43804a20ec 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -32,10 +32,39 @@ #define MULTIPLAYER_API_H #include "core/io/networked_multiplayer_peer.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class MultiplayerAPI : public Reference { - GDCLASS(MultiplayerAPI, Reference); +class MultiplayerAPI : public RefCounted { + GDCLASS(MultiplayerAPI, RefCounted); + +public: + enum RPCMode { + RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) + RPC_MODE_REMOTE, // Using rpc() on it will call method in all remote peers + RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote + RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets + RPC_MODE_REMOTESYNC, // Using rpc() on it will call method in all remote peers and locally + RPC_MODE_MASTERSYNC, // Using rpc() on it will call method in the master peer and locally + RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method in all puppets peers and locally + }; + + struct RPCConfig { + StringName name; + RPCMode rpc_mode = RPC_MODE_DISABLED; + NetworkedMultiplayerPeer::TransferMode transfer_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE; + int channel = 0; + + bool operator==(RPCConfig const &p_other) const { + return name == p_other.name; + } + }; + + struct SortRPCConfig { + StringName::AlphCompare compare; + bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const { + return compare(p_a.name, p_b.name); + } + }; private: //path sent caches @@ -72,10 +101,9 @@ protected: void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len); Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); - void _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len); - void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); + void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount); bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); Error _encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len); @@ -84,7 +112,6 @@ protected: public: enum NetworkCommands { NETWORK_COMMAND_REMOTE_CALL = 0, - NETWORK_COMMAND_REMOTE_SET, NETWORK_COMMAND_SIMPLIFY_PATH, NETWORK_COMMAND_CONFIRM_PATH, NETWORK_COMMAND_RAW, @@ -101,16 +128,6 @@ public: NETWORK_NAME_ID_COMPRESSION_16, }; - enum RPCMode { - RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) - RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers - RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote - RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets - RPC_MODE_REMOTESYNC, // Using rpc() on it will call method / set property in all remote peers and locally - RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally - RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method / set property in all puppets peers and locally - }; - void poll(); void clear(); void set_root_node(Node *p_node); @@ -121,8 +138,6 @@ public: // Called by Node.rpc void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); - // Called by Node.rset - void rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); void _add_peer(int p_id); void _del_peer(int p_id); diff --git a/core/io/net_socket.h b/core/io/net_socket.h index 98ff9562d9..fd7d50c704 100644 --- a/core/io/net_socket.h +++ b/core/io/net_socket.h @@ -32,9 +32,9 @@ #define NET_SOCKET_H #include "core/io/ip.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class NetSocket : public Reference { +class NetSocket : public RefCounted { protected: static NetSocket *(*_create)(); diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp index 52169987fd..cf6a0b6027 100644 --- a/core/io/packed_data_container.cpp +++ b/core/io/packed_data_container.cpp @@ -227,10 +227,10 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd case Variant::VECTOR3: case Variant::TRANSFORM2D: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::BASIS: - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: diff --git a/core/io/packed_data_container.h b/core/io/packed_data_container.h index 7791e21bb3..40772bb2bf 100644 --- a/core/io/packed_data_container.h +++ b/core/io/packed_data_container.h @@ -80,8 +80,8 @@ public: PackedDataContainer() {} }; -class PackedDataContainerRef : public Reference { - GDCLASS(PackedDataContainerRef, Reference); +class PackedDataContainerRef : public RefCounted { + GDCLASS(PackedDataContainerRef, RefCounted); friend class PackedDataContainer; uint32_t offset = 0; diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 9e03c44750..9a345af3d0 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -35,8 +35,8 @@ #include "core/object/class_db.h" #include "core/templates/ring_buffer.h" -class PacketPeer : public Reference { - GDCLASS(PacketPeer, Reference); +class PacketPeer : public RefCounted { + GDCLASS(PacketPeer, RefCounted); Variant _bnd_get_var(bool p_allow_objects = false); diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp index bac98e20e7..a6d220622b 100644 --- a/core/io/packet_peer_dtls.cpp +++ b/core/io/packet_peer_dtls.cpp @@ -30,7 +30,7 @@ #include "packet_peer_dtls.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr; bool PacketPeerDTLS::available = false; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index a0697ca18b..806a95398f 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -31,9 +31,9 @@ #include "pck_packer.h" #include "core/crypto/crypto_core.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION -#include "core/os/file_access.h" #include "core/version.h" static int _get_pad(int p_alignment, int p_n) { @@ -120,7 +120,7 @@ Error PCKPacker::add_file(const String &p_file, const String &p_src, bool p_encr pf.path = p_file; pf.src_path = p_src; pf.ofs = ofs; - pf.size = f->get_len(); + pf.size = f->get_length(); Vector<uint8_t> data = FileAccess::get_file_as_array(p_src); { @@ -236,7 +236,7 @@ Error PCKPacker::flush(bool p_verbose) { } while (to_write > 0) { - int read = src->get_buffer(buf, MIN(to_write, buf_max)); + uint64_t read = src->get_buffer(buf, MIN(to_write, buf_max)); ftmp->store_buffer(buf, read); to_write -= read; } diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index dec8f8748d..3d2ce8f240 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -31,12 +31,12 @@ #ifndef PCK_PACKER_H #define PCK_PACKER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class FileAccess; -class PCKPacker : public Reference { - GDCLASS(PCKPacker, Reference); +class PCKPacker : public RefCounted { + GDCLASS(PCKPacker, RefCounted); FileAccess *file = nullptr; int alignment = 0; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index d46e9edafa..b970e85c99 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -31,9 +31,9 @@ #include "resource.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "scene/main/node.h" //only so casting works diff --git a/core/io/resource.h b/core/io/resource.h index 75a9f928f8..028fed1c6e 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -32,7 +32,7 @@ #define RESOURCE_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/safe_refcount.h" #include "core/templates/self_list.h" @@ -43,8 +43,8 @@ public: \ private: -class Resource : public Reference { - GDCLASS(Resource, Reference); +class Resource : public RefCounted { + GDCLASS(Resource, RefCounted); OBJ_CATEGORY("Resources"); public: diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index c4eb2a20bb..f83ba30514 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -31,10 +31,10 @@ #include "resource_format_binary.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/file_access_compressed.h" #include "core/io/image.h" #include "core/io/marshalls.h" -#include "core/os/dir_access.h" #include "core/version.h" //#define print_bl(m_what) print_line(m_what) @@ -51,7 +51,7 @@ enum { VARIANT_RECT2 = 11, VARIANT_VECTOR3 = 12, VARIANT_PLANE = 13, - VARIANT_QUAT = 14, + VARIANT_QUATERNION = 14, VARIANT_AABB = 15, VARIANT_MATRIX3 = 16, VARIANT_TRANSFORM = 17, @@ -199,8 +199,8 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { v.d = f->get_real(); r_v = v; } break; - case VARIANT_QUAT: { - Quat v; + case VARIANT_QUATERNION: { + Quaternion v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); @@ -245,7 +245,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { } break; case VARIANT_TRANSFORM: { - Transform v; + Transform3D v; v.basis.elements[0].x = f->get_real(); v.basis.elements[0].y = f->get_real(); v.basis.elements[0].z = f->get_real(); @@ -851,7 +851,7 @@ void ResourceLoaderBinary::open(FileAccess *p_f) { bool big_endian = f->get_32(); bool use_real64 = f->get_32(); - f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian + f->set_big_endian(big_endian != 0); //read big endian if saved as big endian uint32_t ver_major = f->get_32(); uint32_t ver_minor = f->get_32(); @@ -948,7 +948,7 @@ String ResourceLoaderBinary::recognize(FileAccess *p_f) { bool big_endian = f->get_32(); f->get_32(); // use_real64 - f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian + f->set_big_endian(big_endian != 0); //read big endian if saved as big endian uint32_t ver_major = f->get_32(); f->get_32(); // ver_minor @@ -1097,13 +1097,13 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons bool big_endian = f->get_32(); bool use_real64 = f->get_32(); - f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian + f->set_big_endian(big_endian != 0); //read big endian if saved as big endian #ifdef BIG_ENDIAN_ENABLED fw->store_32(!big_endian); #else fw->store_32(big_endian); #endif - fw->set_endian_swap(big_endian != 0); + fw->set_big_endian(big_endian != 0); fw->store_32(use_real64); //use real64 uint32_t ver_major = f->get_32(); @@ -1157,8 +1157,8 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons save_ustring(fw, get_ustring(f)); //type - size_t md_ofs = f->get_position(); - size_t importmd_ofs = f->get_64(); + uint64_t md_ofs = f->get_position(); + uint64_t importmd_ofs = f->get_64(); fw->store_64(0); //metadata offset for (int i = 0; i < 14; i++) { @@ -1371,9 +1371,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.d); } break; - case Variant::QUAT: { - f->store_32(VARIANT_QUAT); - Quat val = p_property; + case Variant::QUATERNION: { + f->store_32(VARIANT_QUATERNION); + Quaternion val = p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); @@ -1416,9 +1416,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.elements[2].z); } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { f->store_32(VARIANT_TRANSFORM); - Transform val = p_property; + Transform3D val = p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); @@ -1798,7 +1798,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p if (big_endian) { f->store_32(1); - f->set_endian_swap(true); + f->set_big_endian(true); } else { f->store_32(0); } diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 3592bbdbc4..abc7403935 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -31,9 +31,9 @@ #ifndef RESOURCE_FORMAT_BINARY_H #define RESOURCE_FORMAT_BINARY_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" class ResourceLoaderBinary { bool translation_remapped = false; diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index a14d6ba52c..2ceeb176e5 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -93,8 +93,8 @@ public: ResourceFormatImporter(); }; -class ResourceImporter : public Reference { - GDCLASS(ResourceImporter, Reference); +class ResourceImporter : public RefCounted { + GDCLASS(ResourceImporter, RefCounted); public: virtual String get_importer_name() const = 0; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 040e55b9db..1700766cbf 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -31,8 +31,8 @@ #include "resource_loader.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_importer.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/string/print_string.h" #include "core/string/translation.h" @@ -68,17 +68,17 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ } bool ResourceFormatLoader::handles_type(const String &p_type) const { - if (get_script_instance() && get_script_instance()->has_method("handles_type")) { + if (get_script_instance() && get_script_instance()->has_method("_handles_type")) { // I guess custom loaders for custom resources should use "Resource" - return get_script_instance()->call("handles_type", p_type); + return get_script_instance()->call("_handles_type", p_type); } return false; } String ResourceFormatLoader::get_resource_type(const String &p_path) const { - if (get_script_instance() && get_script_instance()->has_method("get_resource_type")) { - return get_script_instance()->call("get_resource_type", p_path); + if (get_script_instance() && get_script_instance()->has_method("_get_resource_type")) { + return get_script_instance()->call("_get_resource_type", p_path); } return ""; @@ -101,8 +101,8 @@ bool ResourceFormatLoader::exists(const String &p_path) const { } void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const { - if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { - PackedStringArray exts = get_script_instance()->call("get_recognized_extensions"); + if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) { + PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions"); { const String *r = exts.ptr(); @@ -115,8 +115,8 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { // Check user-defined loader if there's any. Hard fail if it returns an error. - if (get_script_instance() && get_script_instance()->has_method("load")) { - Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode); + if (get_script_instance() && get_script_instance()->has_method("_load")) { + Variant res = get_script_instance()->call("_load", p_path, p_original_path, p_use_sub_threads, p_cache_mode); if (res.get_type() == Variant::INT) { // Error code, abort. if (r_error) { @@ -135,8 +135,8 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa } void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - if (get_script_instance() && get_script_instance()->has_method("get_dependencies")) { - PackedStringArray deps = get_script_instance()->call("get_dependencies", p_path, p_add_types); + if (get_script_instance() && get_script_instance()->has_method("_get_dependencies")) { + PackedStringArray deps = get_script_instance()->call("_get_dependencies", p_path, p_add_types); { const String *r = deps.ptr(); @@ -148,13 +148,13 @@ void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> * } Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { - if (get_script_instance() && get_script_instance()->has_method("rename_dependencies")) { + if (get_script_instance() && get_script_instance()->has_method("_rename_dependencies")) { Dictionary deps_dict; for (Map<String, String>::Element *E = p_map.front(); E; E = E->next()) { deps_dict[E->key()] = E->value(); } - int64_t res = get_script_instance()->call("rename_dependencies", deps_dict); + int64_t res = get_script_instance()->call("_rename_dependencies", deps_dict); return (Error)res; } @@ -163,16 +163,16 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map< void ResourceFormatLoader::_bind_methods() { { - MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode")); + MethodInfo info = MethodInfo(Variant::NIL, "_load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode")); info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - ClassDB::add_virtual_method(get_class_static(), info); + BIND_VMETHOD(info); } - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_resource_type", PropertyInfo(Variant::STRING, "path"))); + BIND_VMETHOD(MethodInfo("_get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); + BIND_VMETHOD(MethodInfo(Variant::INT, "_rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE); BIND_ENUM_CONSTANT(CACHE_MODE_REUSE); @@ -354,7 +354,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String & ThreadLoadTask &load_task = thread_load_tasks[local_path]; - if (load_task.resource.is_null()) { //needs to be loaded in thread + if (load_task.resource.is_null()) { //needs to be loaded in thread load_task.semaphore = memnew(Semaphore); if (thread_loading_count < thread_load_max) { @@ -867,7 +867,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem continue; } - String l = res_remaps[i].right(split + 1).strip_edges(); + String l = res_remaps[i].substr(split + 1).strip_edges(); if (l == locale) { // Exact match. new_path = res_remaps[i].left(split); break; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 914d988caa..c656b9a69c 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -35,8 +35,8 @@ #include "core/os/semaphore.h" #include "core/os/thread.h" -class ResourceFormatLoader : public Reference { - GDCLASS(ResourceFormatLoader, Reference); +class ResourceFormatLoader : public RefCounted { + GDCLASS(ResourceFormatLoader, RefCounted); public: enum CacheMode { diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 7ebc7f34b3..389a4fdbbd 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -30,9 +30,9 @@ #include "resource_saver.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS]; @@ -41,24 +41,24 @@ bool ResourceSaver::timestamp_on_save = false; ResourceSavedCallback ResourceSaver::save_callback = nullptr; Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - if (get_script_instance() && get_script_instance()->has_method("save")) { - return (Error)get_script_instance()->call("save", p_path, p_resource, p_flags).operator int64_t(); + if (get_script_instance() && get_script_instance()->has_method("_save")) { + return (Error)get_script_instance()->call("_save", p_path, p_resource, p_flags).operator int64_t(); } return ERR_METHOD_NOT_FOUND; } bool ResourceFormatSaver::recognize(const RES &p_resource) const { - if (get_script_instance() && get_script_instance()->has_method("recognize")) { - return get_script_instance()->call("recognize", p_resource); + if (get_script_instance() && get_script_instance()->has_method("_recognize")) { + return get_script_instance()->call("_recognize", p_resource); } return false; } void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { - PackedStringArray exts = get_script_instance()->call("get_recognized_extensions", p_resource); + if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) { + PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions", p_resource); { const String *r = exts.ptr(); @@ -74,11 +74,11 @@ void ResourceFormatSaver::_bind_methods() { PropertyInfo arg0 = PropertyInfo(Variant::STRING, "path"); PropertyInfo arg1 = PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"); PropertyInfo arg2 = PropertyInfo(Variant::INT, "flags"); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "save", arg0, arg1, arg2)); + BIND_VMETHOD(MethodInfo(Variant::INT, "_save", arg0, arg1, arg2)); } - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); } Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 2c9e8f1aa3..07154aac4d 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -33,8 +33,8 @@ #include "core/io/resource.h" -class ResourceFormatSaver : public Reference { - GDCLASS(ResourceFormatSaver, Reference); +class ResourceFormatSaver : public RefCounted { + GDCLASS(ResourceFormatSaver, RefCounted); protected: static void _bind_methods(); diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index 74154321b3..ee5e9eca0c 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -108,8 +108,8 @@ Array StreamPeer::_get_partial_data(int p_bytes) { return ret; } -void StreamPeer::set_big_endian(bool p_enable) { - big_endian = p_enable; +void StreamPeer::set_big_endian(bool p_big_endian) { + big_endian = p_big_endian; } bool StreamPeer::is_big_endian_enabled() const { diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index dadedbd2dc..effc3850af 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -31,10 +31,10 @@ #ifndef STREAM_PEER_H #define STREAM_PEER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class StreamPeer : public Reference { - GDCLASS(StreamPeer, Reference); +class StreamPeer : public RefCounted { + GDCLASS(StreamPeer, RefCounted); OBJ_CATEGORY("Networking"); protected: @@ -58,7 +58,7 @@ public: virtual int get_available_bytes() const = 0; - void set_big_endian(bool p_enable); + void set_big_endian(bool p_big_endian); bool is_big_endian_enabled() const; void put_8(int8_t p_val); diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index abefa53c6f..10985a04d5 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -36,8 +36,8 @@ #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" -class TCPServer : public Reference { - GDCLASS(TCPServer, Reference); +class TCPServer : public RefCounted { + GDCLASS(TCPServer, RefCounted); protected: enum { diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 9adf912224..83d575cee8 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -30,7 +30,7 @@ #include "translation_loader_po.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/translation.h" #include "core/string/translation_po.h" diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 36d33fcac3..c52820e60d 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -31,8 +31,8 @@ #ifndef TRANSLATION_LOADER_PO_H #define TRANSLATION_LOADER_PO_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/string/translation.h" class TranslationLoaderPO : public ResourceFormatLoader { diff --git a/core/io/udp_server.h b/core/io/udp_server.h index 60d03f37f0..e49a559c51 100644 --- a/core/io/udp_server.h +++ b/core/io/udp_server.h @@ -34,8 +34,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer_udp.h" -class UDPServer : public Reference { - GDCLASS(UDPServer, Reference); +class UDPServer : public RefCounted { + GDCLASS(UDPServer, RefCounted); protected: enum { diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index a1f8e79adc..938d93a01b 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -75,7 +75,7 @@ void XMLParser::_parse_closing_xml_element() { ++P; const char *pBeginClose = P; - while (*P != '>') { + while (*P && *P != '>') { ++P; } @@ -83,7 +83,10 @@ void XMLParser::_parse_closing_xml_element() { #ifdef DEBUG_XML print_line("XML CLOSE: " + node_name); #endif - ++P; + + if (*P) { + ++P; + } } void XMLParser::_ignore_definition() { @@ -91,11 +94,14 @@ void XMLParser::_ignore_definition() { char *F = P; // move until end marked with '>' reached - while (*P != '>') { + while (*P && *P != '>') { ++P; } node_name.parse_utf8(F, P - F); - ++P; + + if (*P) { + ++P; + } } bool XMLParser::_parse_cdata() { @@ -113,6 +119,7 @@ bool XMLParser::_parse_cdata() { } if (!*P) { + node_name = ""; return true; } @@ -131,10 +138,9 @@ bool XMLParser::_parse_cdata() { } if (cDataEnd) { - node_name = String::utf8(cDataBegin, (int)(cDataEnd - cDataBegin)); - } else { - node_name = ""; + cDataEnd = P; } + node_name = String::utf8(cDataBegin, (int)(cDataEnd - cDataBegin)); #ifdef DEBUG_XML print_line("XML CDATA: " + node_name); #endif @@ -146,24 +152,45 @@ void XMLParser::_parse_comment() { node_type = NODE_COMMENT; P += 1; - char *pCommentBegin = P; + char *pEndOfInput = data + length; + char *pCommentBegin; + char *pCommentEnd; - int count = 1; - - // move until end of comment reached - while (count) { - if (*P == '>') { - --count; - } else if (*P == '<') { - ++count; + if (P + 1 < pEndOfInput && P[0] == '-' && P[1] == '-') { + // Comment, use '-->' as end. + pCommentBegin = P + 2; + for (pCommentEnd = pCommentBegin; pCommentEnd + 2 < pEndOfInput; pCommentEnd++) { + if (pCommentEnd[0] == '-' && pCommentEnd[1] == '-' && pCommentEnd[2] == '>') { + break; + } + } + if (pCommentEnd + 2 < pEndOfInput) { + P = pCommentEnd + 3; + } else { + P = pCommentEnd = pEndOfInput; + } + } else { + // Like document type definition, match angle brackets. + pCommentBegin = P; + + int count = 1; + while (*P && count) { + if (*P == '>') { + --count; + } else if (*P == '<') { + ++count; + } + ++P; } - ++P; + if (count) { + pCommentEnd = P; + } else { + pCommentEnd = P - 1; + } } - P -= 3; - node_name = String::utf8(pCommentBegin + 2, (int)(P - pCommentBegin - 2)); - P += 3; + node_name = String::utf8(pCommentBegin, (int)(pCommentEnd - pCommentBegin)); #ifdef DEBUG_XML print_line("XML COMMENT: " + node_name); #endif @@ -178,14 +205,14 @@ void XMLParser::_parse_opening_xml_element() { const char *startName = P; // find end of element - while (*P != '>' && !_is_white_space(*P)) { + while (*P && *P != '>' && !_is_white_space(*P)) { ++P; } const char *endName = P; // find attributes - while (*P != '>') { + while (*P && *P != '>') { if (_is_white_space(*P)) { ++P; } else { @@ -195,10 +222,14 @@ void XMLParser::_parse_opening_xml_element() { // read the attribute names const char *attributeNameBegin = P; - while (!_is_white_space(*P) && *P != '=') { + while (*P && !_is_white_space(*P) && *P != '=') { ++P; } + if (!*P) { + break; + } + const char *attributeNameEnd = P; ++P; @@ -209,7 +240,7 @@ void XMLParser::_parse_opening_xml_element() { } if (!*P) { // malformatted xml file - return; + break; } const char attributeQuoteChar = *P; @@ -221,12 +252,10 @@ void XMLParser::_parse_opening_xml_element() { ++P; } - if (!*P) { // malformatted xml file - return; - } - const char *attributeValueEnd = P; - ++P; + if (*P) { + ++P; + } Attribute attr; attr.name = String::utf8(attributeNameBegin, @@ -258,7 +287,9 @@ void XMLParser::_parse_opening_xml_element() { print_line("XML OPEN: " + node_name); #endif - ++P; + if (*P) { + ++P; + } } void XMLParser::_parse_current_node() { @@ -270,10 +301,6 @@ void XMLParser::_parse_current_node() { ++P; } - if (!*P) { - return; - } - if (P - start > 0) { // we found some text, store it if (_set_text(start, P)) { @@ -281,6 +308,10 @@ void XMLParser::_parse_current_node() { } } + if (!*P) { + return; + } + ++P; // based on current token, parse and report next element @@ -445,7 +476,7 @@ Error XMLParser::open(const String &p_path) { ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'."); - length = file->get_len(); + length = file->get_length(); ERR_FAIL_COND_V(length < 1, ERR_FILE_CORRUPT); if (data) { diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index 847edf958d..1113cce715 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -31,8 +31,8 @@ #ifndef XML_PARSER_H #define XML_PARSER_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/templates/vector.h" @@ -40,8 +40,8 @@ Based on irrXML (see their zlib license). Added mainly for compatibility with their Collada loader. */ -class XMLParser : public Reference { - GDCLASS(XMLParser, Reference); +class XMLParser : public RefCounted { + GDCLASS(XMLParser, RefCounted); public: //! Enumeration of all supported source text file formats @@ -80,7 +80,6 @@ private: Vector<Attribute> attributes; - String _replace_special_characters(const String &origstr); bool _set_text(char *start, char *end); void _parse_closing_xml_element(); void _ignore_definition(); diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp index fe46868dd0..fb4c76aa7a 100644 --- a/core/io/zip_io.cpp +++ b/core/io/zip_io.cpp @@ -68,13 +68,13 @@ long zipio_tell(voidpf opaque, voidpf stream) { long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) { FileAccess *f = *(FileAccess **)opaque; - int pos = offset; + uint64_t pos = offset; switch (origin) { case ZLIB_FILEFUNC_SEEK_CUR: pos = f->get_position() + offset; break; case ZLIB_FILEFUNC_SEEK_END: - pos = f->get_len() + offset; + pos = f->get_length() + offset; break; default: break; diff --git a/core/io/zip_io.h b/core/io/zip_io.h index 52691c65e9..776473bfa1 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -31,7 +31,7 @@ #ifndef ZIP_IO_H #define ZIP_IO_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" // Not directly used in this header, but assumed available in downstream users // like platform/*/export/export.cpp. Could be fixed, but probably better to have diff --git a/core/math/a_star.h b/core/math/a_star.h index 4c61abd91c..44758cb046 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -31,7 +31,7 @@ #ifndef A_STAR_H #define A_STAR_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/oa_hash_map.h" /** @@ -40,8 +40,8 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class AStar : public Reference { - GDCLASS(AStar, Reference); +class AStar : public RefCounted { + GDCLASS(AStar, RefCounted); friend class AStar2D; struct Point { @@ -157,8 +157,8 @@ public: ~AStar(); }; -class AStar2D : public Reference { - GDCLASS(AStar2D, Reference); +class AStar2D : public RefCounted { + GDCLASS(AStar2D, RefCounted); AStar astar; bool _solve(AStar::Point *begin_point, AStar::Point *end_point); diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index 2c721997d8..33aa65f15d 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -392,5 +392,5 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c } AABB::operator String() const { - return String() + position + " - " + size; + return "[P: " + position.operator String() + ", S: " + size + "]"; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 50299902eb..aa3831d4cf 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -109,7 +109,7 @@ bool Basis::is_diagonal() const { } bool Basis::is_rotation() const { - return Math::is_equal_approx(determinant(), 1, UNIT_EPSILON) && is_orthogonal(); + return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal(); } #ifdef MATH_CHECKS @@ -345,12 +345,12 @@ void Basis::rotate(const Vector3 &p_euler) { *this = rotated(p_euler); } -Basis Basis::rotated(const Quat &p_quat) const { - return Basis(p_quat) * (*this); +Basis Basis::rotated(const Quaternion &p_quaternion) const { + return Basis(p_quaternion) * (*this); } -void Basis::rotate(const Quat &p_quat) { - *this = rotated(p_quat); +void Basis::rotate(const Quaternion &p_quaternion) { + *this = rotated(p_quaternion); } Vector3 Basis::get_rotation_euler() const { @@ -367,7 +367,7 @@ Vector3 Basis::get_rotation_euler() const { return m.get_euler(); } -Quat Basis::get_rotation_quat() const { +Quaternion Basis::get_rotation_quaternion() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // See the comment in get_scale() for further information. @@ -378,7 +378,7 @@ Quat Basis::get_rotation_quat() const { m.scale(Vector3(-1, -1, -1)); } - return m.get_quat(); + return m.get_quaternion(); } void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { @@ -756,23 +756,14 @@ bool Basis::operator!=(const Basis &p_matrix) const { } Basis::operator String() const { - String mtx; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (i != 0 || j != 0) { - mtx += ", "; - } - - mtx += rtos(elements[j][i]); //matrix is stored transposed for performance, so print it transposed - } - } - - return mtx; + return "[X: " + get_axis(0).operator String() + + ", Y: " + get_axis(1).operator String() + + ", Z: " + get_axis(2).operator String() + "]"; } -Quat Basis::get_quat() const { +Quaternion Basis::get_quaternion() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_rotation(), Quat(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead."); + ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() instead."); #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; @@ -803,7 +794,7 @@ Quat Basis::get_quat() const { temp[k] = (m.elements[k][i] + m.elements[i][k]) * s; } - return Quat(temp[0], temp[1], temp[2], temp[3]); + return Quaternion(temp[0], temp[1], temp[2], temp[3]); } static const Basis _ortho_bases[24] = { @@ -945,13 +936,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = angle; } -void Basis::set_quat(const Quat &p_quat) { - real_t d = p_quat.length_squared(); +void Basis::set_quaternion(const Quaternion &p_quaternion) { + real_t d = p_quaternion.length_squared(); real_t s = 2.0 / d; - real_t xs = p_quat.x * s, ys = p_quat.y * s, zs = p_quat.z * s; - real_t wx = p_quat.w * xs, wy = p_quat.w * ys, wz = p_quat.w * zs; - real_t xx = p_quat.x * xs, xy = p_quat.x * ys, xz = p_quat.x * zs; - real_t yy = p_quat.y * ys, yz = p_quat.y * zs, zz = p_quat.z * zs; + real_t xs = p_quaternion.x * s, ys = p_quaternion.y * s, zs = p_quaternion.z * s; + real_t wx = p_quaternion.w * xs, wy = p_quaternion.w * ys, wz = p_quaternion.w * zs; + real_t xx = p_quaternion.x * xs, xy = p_quaternion.x * ys, xz = p_quaternion.x * zs; + real_t yy = p_quaternion.y * ys, yz = p_quaternion.y * zs, zz = p_quaternion.z * zs; set(1.0 - (yy + zz), xy - wz, xz + wy, xy + wz, 1.0 - (xx + zz), yz - wx, xz - wy, yz + wx, 1.0 - (xx + yy)); @@ -997,9 +988,9 @@ void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { rotate(p_euler); } -void Basis::set_quat_scale(const Quat &p_quat, const Vector3 &p_scale) { +void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_diagonal(p_scale); - rotate(p_quat); + rotate(p_quaternion); } void Basis::set_diagonal(const Vector3 &p_diag) { @@ -1018,8 +1009,8 @@ void Basis::set_diagonal(const Vector3 &p_diag) { Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { //consider scale - Quat from(*this); - Quat to(p_to); + Quaternion from(*this); + Quaternion to(p_to); Basis b(from.slerp(to, p_weight)); b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight); diff --git a/core/math/basis.h b/core/math/basis.h index 56f6227313..3736047dd3 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -31,7 +31,7 @@ #ifndef BASIS_H #define BASIS_H -#include "core/math/quat.h" +#include "core/math/quaternion.h" #include "core/math/vector3.h" class Basis { @@ -79,13 +79,13 @@ public: void rotate(const Vector3 &p_euler); Basis rotated(const Vector3 &p_euler) const; - void rotate(const Quat &p_quat); - Basis rotated(const Quat &p_quat) const; + void rotate(const Quaternion &p_quaternion); + Basis rotated(const Quaternion &p_quaternion) const; Vector3 get_rotation_euler() 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; - Quat get_rotation_quat() const; + Quaternion get_rotation_quaternion() const; Vector3 get_rotation() const { return get_rotation_euler(); }; Vector3 rotref_posscale_decomposition(Basis &rotref) const; @@ -108,8 +108,8 @@ public: Vector3 get_euler_zyx() const; void set_euler_zyx(const Vector3 &p_euler); - Quat get_quat() const; - void set_quat(const Quat &p_quat); + Quaternion get_quaternion() const; + void set_quaternion(const Quaternion &p_quaternion); Vector3 get_euler() const { return get_euler_yxz(); } void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); } @@ -132,7 +132,7 @@ public: void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale); void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale); - void set_quat_scale(const Quat &p_quat, const Vector3 &p_scale); + void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale); // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { @@ -240,10 +240,10 @@ public: #endif Basis diagonalize(); - operator Quat() const { return get_quat(); } + operator Quaternion() const { return get_quaternion(); } - Basis(const Quat &p_quat) { set_quat(p_quat); }; - Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } + Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }; + Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); } Basis(const Vector3 &p_euler) { set_euler(p_euler); } Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); } diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc index d84c3f7830..afab08f151 100644 --- a/core/math/bvh_logic.inc +++ b/core/math/bvh_logic.inc @@ -20,17 +20,17 @@ void _logic_item_remove_and_reinsert(uint32_t p_ref_id) { // some overlay elaborate way to find out which tree the node is in! BVHHandle temp_handle; temp_handle.set_id(p_ref_id); - _current_tree = _handle_get_tree_id(temp_handle); + uint32_t tree_id = _handle_get_tree_id(temp_handle); // remove and reinsert BVHABB_CLASS abb; - node_remove_item(p_ref_id, &abb); + node_remove_item(p_ref_id, tree_id, &abb); // we must choose where to add to tree - ref.tnode_id = _logic_choose_item_add_node(_root_node_id[_current_tree], abb); + ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); _node_add_item(ref.tnode_id, p_ref_id, abb); - refit_upward_and_balance(ref.tnode_id); + refit_upward_and_balance(ref.tnode_id, tree_id); } // from randy gaul balance function @@ -66,7 +66,7 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) { // https://github.com/RandyGaul/qu3e // It is MODIFIED from qu3e version. // This is the only function used (and _logic_abb_merge helper function). -int32_t _logic_balance(int32_t iA) { +int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) { // return iA; // uncomment this to bypass balance TNode *A = &_nodes[iA]; @@ -107,7 +107,7 @@ int32_t _logic_balance(int32_t iA) { } } else { // check this .. seems dodgy - change_root_node(iC); + change_root_node(iC, p_tree_id); } // Swap A and C @@ -159,7 +159,7 @@ int32_t _logic_balance(int32_t iA) { else { // check this .. seems dodgy - change_root_node(iB); + change_root_node(iB, p_tree_id); } // Swap A and B diff --git a/core/math/bvh_public.inc b/core/math/bvh_public.inc index f1b6d6b1bf..2c1e406712 100644 --- a/core/math/bvh_public.inc +++ b/core/math/bvh_public.inc @@ -53,16 +53,16 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p // assign to handle to return handle.set_id(ref_id); - _current_tree = 0; + uint32_t tree_id = 0; if (p_pairable) { - _current_tree = 1; + tree_id = 1; } - create_root_node(_current_tree); + create_root_node(tree_id); // we must choose where to add to tree if (p_active) { - ref->tnode_id = _logic_choose_item_add_node(_root_node_id[_current_tree], abb); + ref->tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); bool refit = _node_add_item(ref->tnode_id, ref_id, abb); @@ -70,7 +70,7 @@ BVHHandle item_add(T *p_userdata, bool p_active, const Bounds &p_aabb, int32_t p // only need to refit from the parent const TNode &add_node = _nodes[ref->tnode_id]; if (add_node.parent_id != BVHCommon::INVALID) { - refit_upward_and_balance(add_node.parent_id); + refit_upward_and_balance(add_node.parent_id, tree_id); } } } else { @@ -139,13 +139,13 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) { return true; } - _current_tree = _handle_get_tree_id(p_handle); + uint32_t tree_id = _handle_get_tree_id(p_handle); // remove and reinsert - node_remove_item(ref_id); + node_remove_item(ref_id, tree_id); // we must choose where to add to tree - ref.tnode_id = _logic_choose_item_add_node(_root_node_id[_current_tree], abb); + ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); // add to the tree bool needs_refit = _node_add_item(ref.tnode_id, ref_id, abb); @@ -167,7 +167,7 @@ bool item_move(BVHHandle p_handle, const Bounds &p_aabb) { void item_remove(BVHHandle p_handle) { uint32_t ref_id = p_handle.id(); - _current_tree = _handle_get_tree_id(p_handle); + uint32_t tree_id = _handle_get_tree_id(p_handle); VERBOSE_PRINT("item_remove [" + itos(ref_id) + "] "); @@ -187,7 +187,7 @@ void item_remove(BVHHandle p_handle) { // remove the item from the node (only if active) if (_refs[ref_id].is_active()) { - node_remove_item(ref_id); + node_remove_item(ref_id, tree_id); } // remove the item reference @@ -198,10 +198,10 @@ void item_remove(BVHHandle p_handle) { } // don't think refit_all is necessary? - //refit_all(_current_tree); + //refit_all(_tree_id); #ifdef BVH_VERBOSE_TREE - _debug_recursive_print_tree(_current_tree); + _debug_recursive_print_tree(tree_id); #endif } @@ -218,13 +218,13 @@ bool item_activate(BVHHandle p_handle, const Bounds &p_aabb) { BVHABB_CLASS abb; abb.from(p_aabb); - _current_tree = _handle_get_tree_id(p_handle); + uint32_t tree_id = _handle_get_tree_id(p_handle); // we must choose where to add to tree - ref.tnode_id = _logic_choose_item_add_node(_root_node_id[_current_tree], abb); + ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); _node_add_item(ref.tnode_id, ref_id, abb); - refit_upward_and_balance(ref.tnode_id); + refit_upward_and_balance(ref.tnode_id, tree_id); return true; } @@ -238,9 +238,11 @@ bool item_deactivate(BVHHandle p_handle) { return false; } + uint32_t tree_id = _handle_get_tree_id(p_handle); + // remove from tree BVHABB_CLASS abb; - node_remove_item(ref_id, &abb); + node_remove_item(ref_id, tree_id, &abb); // mark as inactive ref.set_inactive(); @@ -304,21 +306,21 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa BVHABB_CLASS abb = leaf.get_aabb(ref.item_id); // make sure current tree is correct prior to changing - _current_tree = _handle_get_tree_id(p_handle); + uint32_t tree_id = _handle_get_tree_id(p_handle); // remove from old tree - node_remove_item(ref_id); + node_remove_item(ref_id, tree_id); // we must set the pairable AFTER getting the current tree // because the pairable status determines which tree ex.pairable = p_pairable; // add to new tree - _current_tree = _handle_get_tree_id(p_handle); - create_root_node(_current_tree); + tree_id = _handle_get_tree_id(p_handle); + create_root_node(tree_id); // we must choose where to add to tree - ref.tnode_id = _logic_choose_item_add_node(_root_node_id[_current_tree], abb); + ref.tnode_id = _logic_choose_item_add_node(_root_node_id[tree_id], abb); bool needs_refit = _node_add_item(ref.tnode_id, ref_id, abb); // only need to refit from the PARENT @@ -326,7 +328,7 @@ bool item_set_pairable(const BVHHandle &p_handle, bool p_pairable, uint32_t p_pa // only need to refit from the parent const TNode &add_node = _nodes[ref.tnode_id]; if (add_node.parent_id != BVHCommon::INVALID) { - refit_upward_and_balance(add_node.parent_id); + refit_upward_and_balance(add_node.parent_id, tree_id); } } } else { diff --git a/core/math/bvh_refit.inc b/core/math/bvh_refit.inc index 514c853ac5..717a3438c7 100644 --- a/core/math/bvh_refit.inc +++ b/core/math/bvh_refit.inc @@ -66,10 +66,10 @@ void refit_upward(uint32_t p_node_id) { } } -void refit_upward_and_balance(uint32_t p_node_id) { +void refit_upward_and_balance(uint32_t p_node_id, uint32_t p_tree_id) { while (p_node_id != BVHCommon::INVALID) { uint32_t before = p_node_id; - p_node_id = _logic_balance(p_node_id); + p_node_id = _logic_balance(p_node_id, p_tree_id); if (before != p_node_id) { VERBOSE_PRINT("REBALANCED!"); diff --git a/core/math/bvh_structs.inc b/core/math/bvh_structs.inc index 4133ba6c10..1d1e0e6468 100644 --- a/core/math/bvh_structs.inc +++ b/core/math/bvh_structs.inc @@ -162,7 +162,6 @@ enum { NUM_TREES = 2, // Tree 1 - Pairable // This is more efficient because in physics we only need check non pairable against the pairable tree. uint32_t _root_node_id[NUM_TREES]; -int _current_tree = 0; // these values may need tweaking according to the project // the bound of the world, and the average velocities of the objects diff --git a/core/math/bvh_tree.h b/core/math/bvh_tree.h index 64c5f6e254..3169d31ec7 100644 --- a/core/math/bvh_tree.h +++ b/core/math/bvh_tree.h @@ -196,7 +196,7 @@ private: new_child.parent_id = p_parent_id; } - void node_remove_child(uint32_t p_parent_id, uint32_t p_child_id, bool p_prevent_sibling = false) { + void node_remove_child(uint32_t p_parent_id, uint32_t p_child_id, uint32_t p_tree_id, bool p_prevent_sibling = false) { TNode &parent = _nodes[p_parent_id]; BVH_ASSERT(!parent.is_leaf()); @@ -231,7 +231,7 @@ private: if (grandparent_id == BVHCommon::INVALID) { if (sibling_present) { // change the root node - change_root_node(sibling_id); + change_root_node(sibling_id, p_tree_id); // delete the old root node as no longer needed _nodes.free(p_parent_id); @@ -243,16 +243,15 @@ private: if (sibling_present) { node_replace_child(grandparent_id, p_parent_id, sibling_id); } else { - node_remove_child(grandparent_id, p_parent_id, true); + node_remove_child(grandparent_id, p_parent_id, p_tree_id, true); } // put the node on the free list to recycle _nodes.free(p_parent_id); } - // this relies on _current_tree being accurate - void change_root_node(uint32_t p_new_root_id) { - _root_node_id[_current_tree] = p_new_root_id; + void change_root_node(uint32_t p_new_root_id, uint32_t p_tree_id) { + _root_node_id[p_tree_id] = p_new_root_id; TNode &root = _nodes[p_new_root_id]; // mark no parent @@ -272,7 +271,7 @@ private: node.neg_leaf_id = -(int)child_leaf_id; } - void node_remove_item(uint32_t p_ref_id, BVHABB_CLASS *r_old_aabb = nullptr) { + void node_remove_item(uint32_t p_ref_id, uint32_t p_tree_id, BVHABB_CLASS *r_old_aabb = nullptr) { // get the reference ItemRef &ref = _refs[p_ref_id]; uint32_t owner_node_id = ref.tnode_id; @@ -336,7 +335,7 @@ private: uint32_t parent_id = tnode.parent_id; - node_remove_child(parent_id, owner_node_id); + node_remove_child(parent_id, owner_node_id, p_tree_id); refit_upward(parent_id); // put the node on the free list to recycle diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 1066cf5e30..66c18f7b3c 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -315,8 +315,8 @@ Vector2 CameraMatrix::get_far_plane_half_extents() const { return Vector2(res.x, res.y); } -bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const { - Vector<Plane> planes = get_projection_planes(Transform()); +bool CameraMatrix::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { + Vector<Plane> planes = get_projection_planes(Transform3D()); const Planes intersections[8][3] = { { PLANE_FAR, PLANE_LEFT, PLANE_TOP }, { PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM }, @@ -338,7 +338,7 @@ bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8point return true; } -Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const { +Vector<Plane> CameraMatrix::get_projection_planes(const Transform3D &p_transform) const { /** Fast Plane Extraction from combined modelview/projection matrices. * References: * https://web.archive.org/web/20011221205252/http://www.markmorley.com/opengl/frustumculling.html @@ -707,8 +707,8 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { matrix[3][3] = 1; } -CameraMatrix::operator Transform() const { - Transform tr; +CameraMatrix::operator Transform3D() const { + Transform3D tr; const real_t *m = &matrix[0][0]; tr.basis.elements[0][0] = m[0]; @@ -730,8 +730,8 @@ CameraMatrix::operator Transform() const { return tr; } -CameraMatrix::CameraMatrix(const Transform &p_transform) { - const Transform &tr = p_transform; +CameraMatrix::CameraMatrix(const Transform3D &p_transform) { + const Transform3D &tr = p_transform; real_t *m = &matrix[0][0]; m[0] = tr.basis.elements[0][0]; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 3f327d3bc4..786d46055a 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -32,7 +32,7 @@ #define CAMERA_MATRIX_H #include "core/math/rect2.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" struct CameraMatrix { enum Planes { @@ -71,9 +71,9 @@ struct CameraMatrix { real_t get_fov() const; bool is_orthogonal() const; - Vector<Plane> get_projection_planes(const Transform &p_transform) const; + Vector<Plane> get_projection_planes(const Transform3D &p_transform) const; - bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const; + bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const; Vector2 get_viewport_half_extents() const; Vector2 get_far_plane_half_extents() const; @@ -90,7 +90,7 @@ struct CameraMatrix { void scale_translate_to_fit(const AABB &p_aabb); void make_scale(const Vector3 &p_scale); int get_pixels_per_meter(int p_for_pixel_width) const; - operator Transform() const; + operator Transform3D() const; void flip_y(); @@ -112,7 +112,7 @@ struct CameraMatrix { float get_lod_multiplier() const; CameraMatrix(); - CameraMatrix(const Transform &p_transform); + CameraMatrix(const Transform3D &p_transform); ~CameraMatrix(); }; diff --git a/core/math/color.cpp b/core/math/color.cpp index 64abd6dd08..dc86cacf8f 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -211,6 +211,14 @@ bool Color::is_equal_approx(const Color &p_color) const { return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); } +Color Color::clamp(const Color &p_min, const Color &p_max) const { + return Color( + CLAMP(r, p_min.r, p_max.r), + CLAMP(g, p_min.g, p_max.g), + CLAMP(b, p_min.b, p_max.b), + CLAMP(a, p_min.a, p_max.a)); +} + void Color::invert() { r = 1.0 - r; g = 1.0 - g; @@ -360,7 +368,7 @@ Color Color::named(const String &p_name) { ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + "."); return Color(); } - return get_named_color(idx); + return named_colors[idx].color; } Color Color::named(const String &p_name, const Color &p_default) { @@ -368,7 +376,7 @@ Color Color::named(const String &p_name, const Color &p_default) { if (idx == -1) { return p_default; } - return get_named_color(idx); + return named_colors[idx].color; } int Color::find_named_color(const String &p_name) { @@ -401,10 +409,12 @@ int Color::get_named_color_count() { } String Color::get_named_color_name(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), ""); return named_colors[p_idx].name; } Color Color::get_named_color(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), Color()); return named_colors[p_idx].color; } @@ -458,7 +468,7 @@ Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { } Color::operator String() const { - return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a); + return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } Color Color::operator+(const Color &p_color) const { diff --git a/core/math/color.h b/core/math/color.h index e404d80c8a..a95dbf4f60 100644 --- a/core/math/color.h +++ b/core/math/color.h @@ -89,6 +89,7 @@ struct Color { bool is_equal_approx(const Color &p_color) const; + Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const; void invert(); Color inverted() const; diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp new file mode 100644 index 0000000000..682a7ea39e --- /dev/null +++ b/core/math/convex_hull.cpp @@ -0,0 +1,2290 @@ +/*************************************************************************/ +/* convex_hull.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +/* + * Based on Godot's patched VHACD-version of Bullet's btConvexHullComputer. + * See /thirdparty/vhacd/btConvexHullComputer.cpp at 64403ddcab9f1dca2408f0a412a22d899708bbb1 + * In turn, based on /src/LinearMath/btConvexHullComputer.cpp in <https://github.com/bulletphysics/bullet3> + * at 73b217fb07e7e3ce126caeb28ab3c9ddd0718467 + * + * Changes: + * - int32_t is consistently used instead of int in some cases + * - integrated patch db0d6c92927f5a1358b887f2645c11f3014f0e8a from Bullet (CWE-190 integer overflow in btConvexHullComputer) + * - adapted to Godot's code style + * - replaced Bullet's types (e.g. vectors) with Godot's + * - replaced custom Pool implementation with PagedAllocator + */ + +/* +Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include "convex_hull.h" + +#include "core/error/error_macros.h" +#include "core/math/aabb.h" +#include "core/math/math_defs.h" +#include "core/os/memory.h" +#include "core/templates/paged_allocator.h" + +#include <string.h> + +//#define DEBUG_CONVEX_HULL +//#define SHOW_ITERATIONS + +// -- GODOT start -- +// Assembly optimizations are not used at the moment. +//#define USE_X86_64_ASM +// -- GODOT end -- + +#ifdef DEBUG_ENABLED +#define CHULL_ASSERT(m_cond) \ + do { \ + if (unlikely(!(m_cond))) { \ + ERR_PRINT("Assertion \"" _STR(m_cond) "\" failed."); \ + } \ + } while (0) +#else +#define CHULL_ASSERT(m_cond) \ + do { \ + } while (0) +#endif + +#if defined(DEBUG_CONVEX_HULL) || defined(SHOW_ITERATIONS) +#include <stdio.h> +#endif + +// Convex hull implementation based on Preparata and Hong +// Ole Kniemeyer, MAXON Computer GmbH +class ConvexHullInternal { +public: + class Point64 { + public: + int64_t x; + int64_t y; + int64_t z; + + Point64(int64_t p_x, int64_t p_y, int64_t p_z) { + x = p_x; + y = p_y; + z = p_z; + } + + bool is_zero() { + return (x == 0) && (y == 0) && (z == 0); + } + + int64_t dot(const Point64 &b) const { + return x * b.x + y * b.y + z * b.z; + } + }; + + class Point32 { + public: + int32_t x = 0; + int32_t y = 0; + int32_t z = 0; + int32_t index = -1; + + Point32() { + } + + Point32(int32_t p_x, int32_t p_y, int32_t p_z) { + x = p_x; + y = p_y; + z = p_z; + } + + bool operator==(const Point32 &b) const { + return (x == b.x) && (y == b.y) && (z == b.z); + } + + bool operator!=(const Point32 &b) const { + return (x != b.x) || (y != b.y) || (z != b.z); + } + + bool is_zero() { + return (x == 0) && (y == 0) && (z == 0); + } + + Point64 cross(const Point32 &b) const { + return Point64((int64_t)y * b.z - (int64_t)z * b.y, (int64_t)z * b.x - (int64_t)x * b.z, (int64_t)x * b.y - (int64_t)y * b.x); + } + + Point64 cross(const Point64 &b) const { + return Point64(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x); + } + + int64_t dot(const Point32 &b) const { + return (int64_t)x * b.x + (int64_t)y * b.y + (int64_t)z * b.z; + } + + int64_t dot(const Point64 &b) const { + return x * b.x + y * b.y + z * b.z; + } + + Point32 operator+(const Point32 &b) const { + return Point32(x + b.x, y + b.y, z + b.z); + } + + Point32 operator-(const Point32 &b) const { + return Point32(x - b.x, y - b.y, z - b.z); + } + }; + + class Int128 { + public: + uint64_t low = 0; + uint64_t high = 0; + + Int128() { + } + + Int128(uint64_t p_low, uint64_t p_high) { + low = p_low; + high = p_high; + } + + Int128(uint64_t p_low) { + low = p_low; + high = 0; + } + + Int128(int64_t p_value) { + low = p_value; + if (p_value >= 0) { + high = 0; + } else { + high = (uint64_t)-1LL; + } + } + + static Int128 mul(int64_t a, int64_t b); + + static Int128 mul(uint64_t a, uint64_t b); + + Int128 operator-() const { + return Int128((uint64_t) - (int64_t)low, ~high + (low == 0)); + } + + Int128 operator+(const Int128 &b) const { +#ifdef USE_X86_64_ASM + Int128 result; + __asm__("addq %[bl], %[rl]\n\t" + "adcq %[bh], %[rh]\n\t" + : [rl] "=r"(result.low), [rh] "=r"(result.high) + : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high) + : "cc"); + return result; +#else + uint64_t lo = low + b.low; + return Int128(lo, high + b.high + (lo < low)); +#endif + } + + Int128 operator-(const Int128 &b) const { +#ifdef USE_X86_64_ASM + Int128 result; + __asm__("subq %[bl], %[rl]\n\t" + "sbbq %[bh], %[rh]\n\t" + : [rl] "=r"(result.low), [rh] "=r"(result.high) + : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high) + : "cc"); + return result; +#else + return *this + -b; +#endif + } + + Int128 &operator+=(const Int128 &b) { +#ifdef USE_X86_64_ASM + __asm__("addq %[bl], %[rl]\n\t" + "adcq %[bh], %[rh]\n\t" + : [rl] "=r"(low), [rh] "=r"(high) + : "0"(low), "1"(high), [bl] "g"(b.low), [bh] "g"(b.high) + : "cc"); +#else + uint64_t lo = low + b.low; + if (lo < low) { + ++high; + } + low = lo; + high += b.high; +#endif + return *this; + } + + Int128 &operator++() { + if (++low == 0) { + ++high; + } + return *this; + } + + Int128 operator*(int64_t b) const; + + real_t to_scalar() const { + return ((int64_t)high >= 0) ? real_t(high) * (real_t(0x100000000LL) * real_t(0x100000000LL)) + real_t(low) : -(-*this).to_scalar(); + } + + int32_t get_sign() const { + return ((int64_t)high < 0) ? -1 : (high || low) ? 1 : + 0; + } + + bool operator<(const Int128 &b) const { + return (high < b.high) || ((high == b.high) && (low < b.low)); + } + + int32_t ucmp(const Int128 &b) const { + if (high < b.high) { + return -1; + } + if (high > b.high) { + return 1; + } + if (low < b.low) { + return -1; + } + if (low > b.low) { + return 1; + } + return 0; + } + }; + + class Rational64 { + private: + uint64_t numerator; + uint64_t denominator; + int32_t sign; + + public: + Rational64(int64_t p_numerator, int64_t p_denominator) { + if (p_numerator > 0) { + sign = 1; + numerator = (uint64_t)p_numerator; + } else if (p_numerator < 0) { + sign = -1; + numerator = (uint64_t)-p_numerator; + } else { + sign = 0; + numerator = 0; + } + if (p_denominator > 0) { + denominator = (uint64_t)p_denominator; + } else if (p_denominator < 0) { + sign = -sign; + denominator = (uint64_t)-p_denominator; + } else { + denominator = 0; + } + } + + bool is_negative_infinity() const { + return (sign < 0) && (denominator == 0); + } + + bool is_nan() const { + return (sign == 0) && (denominator == 0); + } + + int32_t compare(const Rational64 &b) const; + + real_t to_scalar() const { + return sign * ((denominator == 0) ? FLT_MAX : (real_t)numerator / denominator); + } + }; + + class Rational128 { + private: + Int128 numerator; + Int128 denominator; + int32_t sign; + bool is_int_64; + + public: + Rational128(int64_t p_value) { + if (p_value > 0) { + sign = 1; + this->numerator = p_value; + } else if (p_value < 0) { + sign = -1; + this->numerator = -p_value; + } else { + sign = 0; + this->numerator = (uint64_t)0; + } + this->denominator = (uint64_t)1; + is_int_64 = true; + } + + Rational128(const Int128 &p_numerator, const Int128 &p_denominator) { + sign = p_numerator.get_sign(); + if (sign >= 0) { + this->numerator = p_numerator; + } else { + this->numerator = -p_numerator; + } + int32_t dsign = p_denominator.get_sign(); + if (dsign >= 0) { + this->denominator = p_denominator; + } else { + sign = -sign; + this->denominator = -p_denominator; + } + is_int_64 = false; + } + + int32_t compare(const Rational128 &b) const; + + int32_t compare(int64_t b) const; + + real_t to_scalar() const { + return sign * ((denominator.get_sign() == 0) ? FLT_MAX : numerator.to_scalar() / denominator.to_scalar()); + } + }; + + class PointR128 { + public: + Int128 x; + Int128 y; + Int128 z; + Int128 denominator; + + PointR128() { + } + + PointR128(Int128 p_x, Int128 p_y, Int128 p_z, Int128 p_denominator) { + x = p_x; + y = p_y; + z = p_z; + denominator = p_denominator; + } + + real_t xvalue() const { + return x.to_scalar() / denominator.to_scalar(); + } + + real_t yvalue() const { + return y.to_scalar() / denominator.to_scalar(); + } + + real_t zvalue() const { + return z.to_scalar() / denominator.to_scalar(); + } + }; + + class Edge; + class Face; + + class Vertex { + public: + Vertex *next = nullptr; + Vertex *prev = nullptr; + Edge *edges = nullptr; + Face *first_nearby_face = nullptr; + Face *last_nearby_face = nullptr; + PointR128 point128; + Point32 point; + int32_t copy = -1; + + Vertex() { + } + +#ifdef DEBUG_CONVEX_HULL + void print() { + printf("V%d (%d, %d, %d)", point.index, point.x, point.y, point.z); + } + + void print_graph(); +#endif + + Point32 operator-(const Vertex &b) const { + return point - b.point; + } + + Rational128 dot(const Point64 &b) const { + return (point.index >= 0) ? Rational128(point.dot(b)) : Rational128(point128.x * b.x + point128.y * b.y + point128.z * b.z, point128.denominator); + } + + real_t xvalue() const { + return (point.index >= 0) ? real_t(point.x) : point128.xvalue(); + } + + real_t yvalue() const { + return (point.index >= 0) ? real_t(point.y) : point128.yvalue(); + } + + real_t zvalue() const { + return (point.index >= 0) ? real_t(point.z) : point128.zvalue(); + } + + void receive_nearby_faces(Vertex *p_src) { + if (last_nearby_face) { + last_nearby_face->next_with_same_nearby_vertex = p_src->first_nearby_face; + } else { + first_nearby_face = p_src->first_nearby_face; + } + if (p_src->last_nearby_face) { + last_nearby_face = p_src->last_nearby_face; + } + for (Face *f = p_src->first_nearby_face; f; f = f->next_with_same_nearby_vertex) { + CHULL_ASSERT(f->nearby_vertex == p_src); + f->nearby_vertex = this; + } + p_src->first_nearby_face = nullptr; + p_src->last_nearby_face = nullptr; + } + }; + + class Edge { + public: + Edge *next = nullptr; + Edge *prev = nullptr; + Edge *reverse = nullptr; + Vertex *target = nullptr; + Face *face = nullptr; + int32_t copy = -1; + + void link(Edge *n) { + CHULL_ASSERT(reverse->target == n->reverse->target); + next = n; + n->prev = this; + } + +#ifdef DEBUG_CONVEX_HULL + void print() { + printf("E%p : %d -> %d, n=%p p=%p (0 %d\t%d\t%d) -> (%d %d %d)", this, reverse->target->point.index, target->point.index, next, prev, + reverse->target->point.x, reverse->target->point.y, reverse->target->point.z, target->point.x, target->point.y, target->point.z); + } +#endif + }; + + class Face { + public: + Face *next = nullptr; + Vertex *nearby_vertex = nullptr; + Face *next_with_same_nearby_vertex = nullptr; + Point32 origin; + Point32 dir0; + Point32 dir1; + + Face() { + } + + void init(Vertex *p_a, Vertex *p_b, Vertex *p_c) { + nearby_vertex = p_a; + origin = p_a->point; + dir0 = *p_b - *p_a; + dir1 = *p_c - *p_a; + if (p_a->last_nearby_face) { + p_a->last_nearby_face->next_with_same_nearby_vertex = this; + } else { + p_a->first_nearby_face = this; + } + p_a->last_nearby_face = this; + } + + Point64 get_normal() { + return dir0.cross(dir1); + } + }; + + template <typename UWord, typename UHWord> + class DMul { + private: + static uint32_t high(uint64_t p_value) { + return (uint32_t)(p_value >> 32); + } + + static uint32_t low(uint64_t p_value) { + return (uint32_t)p_value; + } + + static uint64_t mul(uint32_t a, uint32_t b) { + return (uint64_t)a * (uint64_t)b; + } + + static void shl_half(uint64_t &p_value) { + p_value <<= 32; + } + + static uint64_t high(Int128 p_value) { + return p_value.high; + } + + static uint64_t low(Int128 p_value) { + return p_value.low; + } + + static Int128 mul(uint64_t a, uint64_t b) { + return Int128::mul(a, b); + } + + static void shl_half(Int128 &p_value) { + p_value.high = p_value.low; + p_value.low = 0; + } + + public: + static void mul(UWord p_a, UWord p_b, UWord &r_low, UWord &r_high) { + UWord p00 = mul(low(p_a), low(p_b)); + UWord p01 = mul(low(p_a), high(p_b)); + UWord p10 = mul(high(p_a), low(p_b)); + UWord p11 = mul(high(p_a), high(p_b)); + UWord p0110 = UWord(low(p01)) + UWord(low(p10)); + p11 += high(p01); + p11 += high(p10); + p11 += high(p0110); + shl_half(p0110); + p00 += p0110; + if (p00 < p0110) { + ++p11; + } + r_low = p00; + r_high = p11; + } + }; + +private: + class IntermediateHull { + public: + Vertex *min_xy = nullptr; + Vertex *max_xy = nullptr; + Vertex *min_yx = nullptr; + Vertex *max_yx = nullptr; + + IntermediateHull() { + } + + void print(); + }; + + enum Orientation { NONE, + CLOCKWISE, + COUNTER_CLOCKWISE }; + + Vector3 scaling; + Vector3 center; + PagedAllocator<Vertex> vertex_pool; + PagedAllocator<Edge> edge_pool; + PagedAllocator<Face> face_pool; + LocalVector<Vertex *> original_vertices; + int32_t merge_stamp = 0; + int32_t min_axis = 0; + int32_t med_axis = 0; + int32_t max_axis = 0; + int32_t used_edge_pairs = 0; + int32_t max_used_edge_pairs = 0; + + static Orientation get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t); + Edge *find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_ssxrxs, Rational64 &p_min_cot); + void find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, Vertex *p_stop0, Vertex *p_stop1); + + Edge *new_edge_pair(Vertex *p_from, Vertex *p_to); + + void remove_edge_pair(Edge *p_edge) { + Edge *n = p_edge->next; + Edge *r = p_edge->reverse; + + CHULL_ASSERT(p_edge->target && r->target); + + if (n != p_edge) { + n->prev = p_edge->prev; + p_edge->prev->next = n; + r->target->edges = n; + } else { + r->target->edges = nullptr; + } + + n = r->next; + + if (n != r) { + n->prev = r->prev; + r->prev->next = n; + p_edge->target->edges = n; + } else { + p_edge->target->edges = nullptr; + } + + edge_pool.free(p_edge); + edge_pool.free(r); + used_edge_pairs--; + } + + void compute_internal(int32_t p_start, int32_t p_end, IntermediateHull &r_result); + + bool merge_projection(IntermediateHull &p_h0, IntermediateHull &p_h1, Vertex *&r_c0, Vertex *&r_c1); + + void merge(IntermediateHull &p_h0, IntermediateHull &p_h1); + + Vector3 to_gd_vector(const Point32 &p_v); + + Vector3 get_gd_normal(Face *p_face); + + bool shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack); + +public: + ~ConvexHullInternal() { + vertex_pool.reset(true); + edge_pool.reset(true); + face_pool.reset(true); + } + + Vertex *vertex_list; + + void compute(const Vector3 *p_coords, int32_t p_count); + + Vector3 get_coordinates(const Vertex *p_v); + + real_t shrink(real_t amount, real_t p_clamp_amount); +}; + +ConvexHullInternal::Int128 ConvexHullInternal::Int128::operator*(int64_t b) const { + bool negative = (int64_t)high < 0; + Int128 a = negative ? -*this : *this; + if (b < 0) { + negative = !negative; + b = -b; + } + Int128 result = mul(a.low, (uint64_t)b); + result.high += a.high * (uint64_t)b; + return negative ? -result : result; +} + +ConvexHullInternal::Int128 ConvexHullInternal::Int128::mul(int64_t a, int64_t b) { + Int128 result; + +#ifdef USE_X86_64_ASM + __asm__("imulq %[b]" + : "=a"(result.low), "=d"(result.high) + : "0"(a), [b] "r"(b) + : "cc"); + return result; + +#else + bool negative = a < 0; + if (negative) { + a = -a; + } + if (b < 0) { + negative = !negative; + b = -b; + } + DMul<uint64_t, uint32_t>::mul((uint64_t)a, (uint64_t)b, result.low, result.high); + return negative ? -result : result; +#endif +} + +ConvexHullInternal::Int128 ConvexHullInternal::Int128::mul(uint64_t a, uint64_t b) { + Int128 result; + +#ifdef USE_X86_64_ASM + __asm__("mulq %[b]" + : "=a"(result.low), "=d"(result.high) + : "0"(a), [b] "r"(b) + : "cc"); + +#else + DMul<uint64_t, uint32_t>::mul(a, b, result.low, result.high); +#endif + + return result; +} + +int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const { + if (sign != b.sign) { + return sign - b.sign; + } else if (sign == 0) { + return 0; + } + + // return (numerator * b.denominator > b.numerator * denominator) ? sign : (numerator * b.denominator < b.numerator * denominator) ? -sign : 0; + +#ifdef USE_X86_64_ASM + + int32_t result; + int64_t tmp; + int64_t dummy; + __asm__("mulq %[bn]\n\t" + "movq %%rax, %[tmp]\n\t" + "movq %%rdx, %%rbx\n\t" + "movq %[tn], %%rax\n\t" + "mulq %[bd]\n\t" + "subq %[tmp], %%rax\n\t" + "sbbq %%rbx, %%rdx\n\t" // rdx:rax contains 128-bit-difference "numerator*b.denominator - b.numerator*denominator" + "setnsb %%bh\n\t" // bh=1 if difference is non-negative, bh=0 otherwise + "orq %%rdx, %%rax\n\t" + "setnzb %%bl\n\t" // bl=1 if difference if non-zero, bl=0 if it is zero + "decb %%bh\n\t" // now bx=0x0000 if difference is zero, 0xff01 if it is negative, 0x0001 if it is positive (i.e., same sign as difference) + "shll $16, %%ebx\n\t" // ebx has same sign as difference + : "=&b"(result), [tmp] "=&r"(tmp), "=a"(dummy) + : "a"(denominator), [bn] "g"(b.numerator), [tn] "g"(numerator), [bd] "g"(b.denominator) + : "%rdx", "cc"); + return result ? result ^ sign // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero) + // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero) + : + 0; + +#else + + return sign * Int128::mul(numerator, b.denominator).ucmp(Int128::mul(denominator, b.numerator)); + +#endif +} + +int32_t ConvexHullInternal::Rational128::compare(const Rational128 &b) const { + if (sign != b.sign) { + return sign - b.sign; + } else if (sign == 0) { + return 0; + } + if (is_int_64) { + return -b.compare(sign * (int64_t)numerator.low); + } + + Int128 nbd_low, nbd_high, dbn_low, dbn_high; + DMul<Int128, uint64_t>::mul(numerator, b.denominator, nbd_low, nbd_high); + DMul<Int128, uint64_t>::mul(denominator, b.numerator, dbn_low, dbn_high); + + int32_t cmp = nbd_high.ucmp(dbn_high); + if (cmp) { + return cmp * sign; + } + return nbd_low.ucmp(dbn_low) * sign; +} + +int32_t ConvexHullInternal::Rational128::compare(int64_t b) const { + if (is_int_64) { + int64_t a = sign * (int64_t)numerator.low; + return (a > b) ? 1 : (a < b) ? -1 : + 0; + } + if (b > 0) { + if (sign <= 0) { + return -1; + } + } else if (b < 0) { + if (sign >= 0) { + return 1; + } + b = -b; + } else { + return sign; + } + + return numerator.ucmp(denominator * b) * sign; +} + +ConvexHullInternal::Edge *ConvexHullInternal::new_edge_pair(Vertex *p_from, Vertex *p_to) { + CHULL_ASSERT(p_from && p_to); + Edge *e = edge_pool.alloc(); + Edge *r = edge_pool.alloc(); + e->reverse = r; + r->reverse = e; + e->copy = merge_stamp; + r->copy = merge_stamp; + e->target = p_to; + r->target = p_from; + e->face = nullptr; + r->face = nullptr; + used_edge_pairs++; + if (used_edge_pairs > max_used_edge_pairs) { + max_used_edge_pairs = used_edge_pairs; + } + return e; +} + +bool ConvexHullInternal::merge_projection(IntermediateHull &r_h0, IntermediateHull &r_h1, Vertex *&r_c0, Vertex *&r_c1) { + Vertex *v0 = r_h0.max_yx; + Vertex *v1 = r_h1.min_yx; + if ((v0->point.x == v1->point.x) && (v0->point.y == v1->point.y)) { + CHULL_ASSERT(v0->point.z < v1->point.z); + Vertex *v1p = v1->prev; + if (v1p == v1) { + r_c0 = v0; + if (v1->edges) { + CHULL_ASSERT(v1->edges->next == v1->edges); + v1 = v1->edges->target; + CHULL_ASSERT(v1->edges->next == v1->edges); + } + r_c1 = v1; + return false; + } + Vertex *v1n = v1->next; + v1p->next = v1n; + v1n->prev = v1p; + if (v1 == r_h1.min_xy) { + if ((v1n->point.x < v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y < v1p->point.y))) { + r_h1.min_xy = v1n; + } else { + r_h1.min_xy = v1p; + } + } + if (v1 == r_h1.max_xy) { + if ((v1n->point.x > v1p->point.x) || ((v1n->point.x == v1p->point.x) && (v1n->point.y > v1p->point.y))) { + r_h1.max_xy = v1n; + } else { + r_h1.max_xy = v1p; + } + } + } + + v0 = r_h0.max_xy; + v1 = r_h1.max_xy; + Vertex *v00 = nullptr; + Vertex *v10 = nullptr; + int32_t sign = 1; + + for (int32_t side = 0; side <= 1; side++) { + int32_t dx = (v1->point.x - v0->point.x) * sign; + if (dx > 0) { + while (true) { + int32_t dy = v1->point.y - v0->point.y; + + Vertex *w0 = side ? v0->next : v0->prev; + if (w0 != v0) { + int32_t dx0 = (w0->point.x - v0->point.x) * sign; + int32_t dy0 = w0->point.y - v0->point.y; + if ((dy0 <= 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx <= dy * dx0)))) { + v0 = w0; + dx = (v1->point.x - v0->point.x) * sign; + continue; + } + } + + Vertex *w1 = side ? v1->next : v1->prev; + if (w1 != v1) { + int32_t dx1 = (w1->point.x - v1->point.x) * sign; + int32_t dy1 = w1->point.y - v1->point.y; + int32_t dxn = (w1->point.x - v0->point.x) * sign; + if ((dxn > 0) && (dy1 < 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx < dy * dx1)))) { + v1 = w1; + dx = dxn; + continue; + } + } + + break; + } + } else if (dx < 0) { + while (true) { + int32_t dy = v1->point.y - v0->point.y; + + Vertex *w1 = side ? v1->prev : v1->next; + if (w1 != v1) { + int32_t dx1 = (w1->point.x - v1->point.x) * sign; + int32_t dy1 = w1->point.y - v1->point.y; + if ((dy1 >= 0) && ((dx1 == 0) || ((dx1 < 0) && (dy1 * dx <= dy * dx1)))) { + v1 = w1; + dx = (v1->point.x - v0->point.x) * sign; + continue; + } + } + + Vertex *w0 = side ? v0->prev : v0->next; + if (w0 != v0) { + int32_t dx0 = (w0->point.x - v0->point.x) * sign; + int32_t dy0 = w0->point.y - v0->point.y; + int32_t dxn = (v1->point.x - w0->point.x) * sign; + if ((dxn < 0) && (dy0 > 0) && ((dx0 == 0) || ((dx0 < 0) && (dy0 * dx < dy * dx0)))) { + v0 = w0; + dx = dxn; + continue; + } + } + + break; + } + } else { + int32_t x = v0->point.x; + int32_t y0 = v0->point.y; + Vertex *w0 = v0; + Vertex *t; + while (((t = side ? w0->next : w0->prev) != v0) && (t->point.x == x) && (t->point.y <= y0)) { + w0 = t; + y0 = t->point.y; + } + v0 = w0; + + int32_t y1 = v1->point.y; + Vertex *w1 = v1; + while (((t = side ? w1->prev : w1->next) != v1) && (t->point.x == x) && (t->point.y >= y1)) { + w1 = t; + y1 = t->point.y; + } + v1 = w1; + } + + if (side == 0) { + v00 = v0; + v10 = v1; + + v0 = r_h0.min_xy; + v1 = r_h1.min_xy; + sign = -1; + } + } + + v0->prev = v1; + v1->next = v0; + + v00->next = v10; + v10->prev = v00; + + if (r_h1.min_xy->point.x < r_h0.min_xy->point.x) { + r_h0.min_xy = r_h1.min_xy; + } + if (r_h1.max_xy->point.x >= r_h0.max_xy->point.x) { + r_h0.max_xy = r_h1.max_xy; + } + + r_h0.max_yx = r_h1.max_yx; + + r_c0 = v00; + r_c1 = v10; + + return true; +} + +void ConvexHullInternal::compute_internal(int32_t p_start, int32_t p_end, IntermediateHull &r_result) { + int32_t n = p_end - p_start; + switch (n) { + case 0: + r_result.min_xy = nullptr; + r_result.max_xy = nullptr; + r_result.min_yx = nullptr; + r_result.max_yx = nullptr; + return; + case 2: { + Vertex *v = original_vertices[p_start]; + Vertex *w = original_vertices[p_start + 1]; + if (v->point != w->point) { + int32_t dx = v->point.x - w->point.x; + int32_t dy = v->point.y - w->point.y; + + if ((dx == 0) && (dy == 0)) { + if (v->point.z > w->point.z) { + Vertex *t = w; + w = v; + v = t; + } + CHULL_ASSERT(v->point.z < w->point.z); + v->next = v; + v->prev = v; + r_result.min_xy = v; + r_result.max_xy = v; + r_result.min_yx = v; + r_result.max_yx = v; + } else { + v->next = w; + v->prev = w; + w->next = v; + w->prev = v; + + if ((dx < 0) || ((dx == 0) && (dy < 0))) { + r_result.min_xy = v; + r_result.max_xy = w; + } else { + r_result.min_xy = w; + r_result.max_xy = v; + } + + if ((dy < 0) || ((dy == 0) && (dx < 0))) { + r_result.min_yx = v; + r_result.max_yx = w; + } else { + r_result.min_yx = w; + r_result.max_yx = v; + } + } + + Edge *e = new_edge_pair(v, w); + e->link(e); + v->edges = e; + + e = e->reverse; + e->link(e); + w->edges = e; + + return; + } + [[fallthrough]]; + } + case 1: { + Vertex *v = original_vertices[p_start]; + v->edges = nullptr; + v->next = v; + v->prev = v; + + r_result.min_xy = v; + r_result.max_xy = v; + r_result.min_yx = v; + r_result.max_yx = v; + + return; + } + } + + int32_t split0 = p_start + n / 2; + Point32 p = original_vertices[split0 - 1]->point; + int32_t split1 = split0; + while ((split1 < p_end) && (original_vertices[split1]->point == p)) { + split1++; + } + compute_internal(p_start, split0, r_result); + IntermediateHull hull1; + compute_internal(split1, p_end, hull1); +#ifdef DEBUG_CONVEX_HULL + printf("\n\nMerge\n"); + r_result.print(); + hull1.print(); +#endif + merge(r_result, hull1); +#ifdef DEBUG_CONVEX_HULL + printf("\n Result\n"); + r_result.print(); +#endif +} + +#ifdef DEBUG_CONVEX_HULL +void ConvexHullInternal::IntermediateHull::print() { + printf(" Hull\n"); + for (Vertex *v = min_xy; v;) { + printf(" "); + v->print(); + if (v == max_xy) { + printf(" max_xy"); + } + if (v == min_yx) { + printf(" min_yx"); + } + if (v == max_yx) { + printf(" max_yx"); + } + if (v->next->prev != v) { + printf(" Inconsistency"); + } + printf("\n"); + v = v->next; + if (v == min_xy) { + break; + } + } + if (min_xy) { + min_xy->copy = (min_xy->copy == -1) ? -2 : -1; + min_xy->print_graph(); + } +} + +void ConvexHullInternal::Vertex::print_graph() { + print(); + printf("\nEdges\n"); + Edge *e = edges; + if (e) { + do { + e->print(); + printf("\n"); + e = e->next; + } while (e != edges); + do { + Vertex *v = e->target; + if (v->copy != copy) { + v->copy = copy; + v->print_graph(); + } + e = e->next; + } while (e != edges); + } +} +#endif + +ConvexHullInternal::Orientation ConvexHullInternal::get_orientation(const Edge *p_prev, const Edge *p_next, const Point32 &p_s, const Point32 &p_t) { + CHULL_ASSERT(p_prev->reverse->target == p_next->reverse->target); + if (p_prev->next == p_next) { + if (p_prev->prev == p_next) { + Point64 n = p_t.cross(p_s); + Point64 m = (*p_prev->target - *p_next->reverse->target).cross(*p_next->target - *p_next->reverse->target); + CHULL_ASSERT(!m.is_zero()); + int64_t dot = n.dot(m); + CHULL_ASSERT(dot != 0); + return (dot > 0) ? COUNTER_CLOCKWISE : CLOCKWISE; + } + return COUNTER_CLOCKWISE; + } else if (p_prev->prev == p_next) { + return CLOCKWISE; + } else { + return NONE; + } +} + +ConvexHullInternal::Edge *ConvexHullInternal::find_max_angle(bool p_ccw, const Vertex *p_start, const Point32 &p_s, const Point64 &p_rxs, const Point64 &p_sxrxs, Rational64 &p_min_cot) { + Edge *min_edge = nullptr; + +#ifdef DEBUG_CONVEX_HULL + printf("find max edge for %d\n", p_start->point.index); +#endif + Edge *e = p_start->edges; + if (e) { + do { + if (e->copy > merge_stamp) { + Point32 t = *e->target - *p_start; + Rational64 cot(t.dot(p_sxrxs), t.dot(p_rxs)); +#ifdef DEBUG_CONVEX_HULL + printf(" Angle is %f (%d) for ", Math::atan(cot.to_scalar()), (int32_t)cot.is_nan()); + e->print(); +#endif + if (cot.is_nan()) { + CHULL_ASSERT(p_ccw ? (t.dot(p_s) < 0) : (t.dot(p_s) > 0)); + } else { + int32_t cmp; + if (min_edge == nullptr) { + p_min_cot = cot; + min_edge = e; + } else if ((cmp = cot.compare(p_min_cot)) < 0) { + p_min_cot = cot; + min_edge = e; + } else if ((cmp == 0) && (p_ccw == (get_orientation(min_edge, e, p_s, t) == COUNTER_CLOCKWISE))) { + min_edge = e; + } + } +#ifdef DEBUG_CONVEX_HULL + printf("\n"); +#endif + } + e = e->next; + } while (e != p_start->edges); + } + return min_edge; +} + +void ConvexHullInternal::find_edge_for_coplanar_faces(Vertex *p_c0, Vertex *p_c1, Edge *&p_e0, Edge *&p_e1, Vertex *p_stop0, Vertex *p_stop1) { + Edge *start0 = p_e0; + Edge *start1 = p_e1; + Point32 et0 = start0 ? start0->target->point : p_c0->point; + Point32 et1 = start1 ? start1->target->point : p_c1->point; + Point32 s = p_c1->point - p_c0->point; + Point64 normal = ((start0 ? start0 : start1)->target->point - p_c0->point).cross(s); + int64_t dist = p_c0->point.dot(normal); + CHULL_ASSERT(!start1 || (start1->target->point.dot(normal) == dist)); + Point64 perp = s.cross(normal); + CHULL_ASSERT(!perp.is_zero()); + +#ifdef DEBUG_CONVEX_HULL + printf(" Advancing %d %d (%p %p, %d %d)\n", p_c0->point.index, p_c1->point.index, start0, start1, start0 ? start0->target->point.index : -1, start1 ? start1->target->point.index : -1); +#endif + + int64_t max_dot0 = et0.dot(perp); + if (p_e0) { + while (p_e0->target != p_stop0) { + Edge *e = p_e0->reverse->prev; + if (e->target->point.dot(normal) < dist) { + break; + } + CHULL_ASSERT(e->target->point.dot(normal) == dist); + if (e->copy == merge_stamp) { + break; + } + int64_t dot = e->target->point.dot(perp); + if (dot <= max_dot0) { + break; + } + max_dot0 = dot; + p_e0 = e; + et0 = e->target->point; + } + } + + int64_t max_dot1 = et1.dot(perp); + if (p_e1) { + while (p_e1->target != p_stop1) { + Edge *e = p_e1->reverse->next; + if (e->target->point.dot(normal) < dist) { + break; + } + CHULL_ASSERT(e->target->point.dot(normal) == dist); + if (e->copy == merge_stamp) { + break; + } + int64_t dot = e->target->point.dot(perp); + if (dot <= max_dot1) { + break; + } + max_dot1 = dot; + p_e1 = e; + et1 = e->target->point; + } + } + +#ifdef DEBUG_CONVEX_HULL + printf(" Starting at %d %d\n", et0.index, et1.index); +#endif + + int64_t dx = max_dot1 - max_dot0; + if (dx > 0) { + while (true) { + int64_t dy = (et1 - et0).dot(s); + + if (p_e0 && (p_e0->target != p_stop0)) { + Edge *f0 = p_e0->next->reverse; + if (f0->copy > merge_stamp) { + int64_t dx0 = (f0->target->point - et0).dot(perp); + int64_t dy0 = (f0->target->point - et0).dot(s); + if ((dx0 == 0) ? (dy0 < 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) >= 0))) { + et0 = f0->target->point; + dx = (et1 - et0).dot(perp); + p_e0 = (p_e0 == start0) ? nullptr : f0; + continue; + } + } + } + + if (p_e1 && (p_e1->target != p_stop1)) { + Edge *f1 = p_e1->reverse->next; + if (f1->copy > merge_stamp) { + Point32 d1 = f1->target->point - et1; + if (d1.dot(normal) == 0) { + int64_t dx1 = d1.dot(perp); + int64_t dy1 = d1.dot(s); + int64_t dxn = (f1->target->point - et0).dot(perp); + if ((dxn > 0) && ((dx1 == 0) ? (dy1 < 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) > 0)))) { + p_e1 = f1; + et1 = p_e1->target->point; + dx = dxn; + continue; + } + } else { + CHULL_ASSERT((p_e1 == start1) && (d1.dot(normal) < 0)); + } + } + } + + break; + } + } else if (dx < 0) { + while (true) { + int64_t dy = (et1 - et0).dot(s); + + if (p_e1 && (p_e1->target != p_stop1)) { + Edge *f1 = p_e1->prev->reverse; + if (f1->copy > merge_stamp) { + int64_t dx1 = (f1->target->point - et1).dot(perp); + int64_t dy1 = (f1->target->point - et1).dot(s); + if ((dx1 == 0) ? (dy1 > 0) : ((dx1 < 0) && (Rational64(dy1, dx1).compare(Rational64(dy, dx)) <= 0))) { + et1 = f1->target->point; + dx = (et1 - et0).dot(perp); + p_e1 = (p_e1 == start1) ? nullptr : f1; + continue; + } + } + } + + if (p_e0 && (p_e0->target != p_stop0)) { + Edge *f0 = p_e0->reverse->prev; + if (f0->copy > merge_stamp) { + Point32 d0 = f0->target->point - et0; + if (d0.dot(normal) == 0) { + int64_t dx0 = d0.dot(perp); + int64_t dy0 = d0.dot(s); + int64_t dxn = (et1 - f0->target->point).dot(perp); + if ((dxn < 0) && ((dx0 == 0) ? (dy0 > 0) : ((dx0 < 0) && (Rational64(dy0, dx0).compare(Rational64(dy, dx)) < 0)))) { + p_e0 = f0; + et0 = p_e0->target->point; + dx = dxn; + continue; + } + } else { + CHULL_ASSERT((p_e0 == start0) && (d0.dot(normal) < 0)); + } + } + } + + break; + } + } +#ifdef DEBUG_CONVEX_HULL + printf(" Advanced edges to %d %d\n", et0.index, et1.index); +#endif +} + +void ConvexHullInternal::merge(IntermediateHull &p_h0, IntermediateHull &p_h1) { + if (!p_h1.max_xy) { + return; + } + if (!p_h0.max_xy) { + p_h0 = p_h1; + return; + } + + merge_stamp--; + + Vertex *c0 = nullptr; + Edge *to_prev0 = nullptr; + Edge *first_new0 = nullptr; + Edge *pending_head0 = nullptr; + Edge *pending_tail0 = nullptr; + Vertex *c1 = nullptr; + Edge *to_prev1 = nullptr; + Edge *first_new1 = nullptr; + Edge *pending_head1 = nullptr; + Edge *pending_tail1 = nullptr; + Point32 prev_point; + + if (merge_projection(p_h0, p_h1, c0, c1)) { + Point32 s = *c1 - *c0; + Point64 normal = Point32(0, 0, -1).cross(s); + Point64 t = s.cross(normal); + CHULL_ASSERT(!t.is_zero()); + + Edge *e = c0->edges; + Edge *start0 = nullptr; + if (e) { + do { + int64_t dot = (*e->target - *c0).dot(normal); + CHULL_ASSERT(dot <= 0); + if ((dot == 0) && ((*e->target - *c0).dot(t) > 0)) { + if (!start0 || (get_orientation(start0, e, s, Point32(0, 0, -1)) == CLOCKWISE)) { + start0 = e; + } + } + e = e->next; + } while (e != c0->edges); + } + + e = c1->edges; + Edge *start1 = nullptr; + if (e) { + do { + int64_t dot = (*e->target - *c1).dot(normal); + CHULL_ASSERT(dot <= 0); + if ((dot == 0) && ((*e->target - *c1).dot(t) > 0)) { + if (!start1 || (get_orientation(start1, e, s, Point32(0, 0, -1)) == COUNTER_CLOCKWISE)) { + start1 = e; + } + } + e = e->next; + } while (e != c1->edges); + } + + if (start0 || start1) { + find_edge_for_coplanar_faces(c0, c1, start0, start1, nullptr, nullptr); + if (start0) { + c0 = start0->target; + } + if (start1) { + c1 = start1->target; + } + } + + prev_point = c1->point; + prev_point.z++; + } else { + prev_point = c1->point; + prev_point.x++; + } + + Vertex *first0 = c0; + Vertex *first1 = c1; + bool first_run = true; + + while (true) { + Point32 s = *c1 - *c0; + Point32 r = prev_point - c0->point; + Point64 rxs = r.cross(s); + Point64 sxrxs = s.cross(rxs); + +#ifdef DEBUG_CONVEX_HULL + printf("\n Checking %d %d\n", c0->point.index, c1->point.index); +#endif + Rational64 min_cot0(0, 0); + Edge *min0 = find_max_angle(false, c0, s, rxs, sxrxs, min_cot0); + Rational64 min_cot1(0, 0); + Edge *min1 = find_max_angle(true, c1, s, rxs, sxrxs, min_cot1); + if (!min0 && !min1) { + Edge *e = new_edge_pair(c0, c1); + e->link(e); + c0->edges = e; + + e = e->reverse; + e->link(e); + c1->edges = e; + return; + } else { + int32_t cmp = !min0 ? 1 : !min1 ? -1 : + min_cot0.compare(min_cot1); +#ifdef DEBUG_CONVEX_HULL + printf(" -> Result %d\n", cmp); +#endif + if (first_run || ((cmp >= 0) ? !min_cot1.is_negative_infinity() : !min_cot0.is_negative_infinity())) { + Edge *e = new_edge_pair(c0, c1); + if (pending_tail0) { + pending_tail0->prev = e; + } else { + pending_head0 = e; + } + e->next = pending_tail0; + pending_tail0 = e; + + e = e->reverse; + if (pending_tail1) { + pending_tail1->next = e; + } else { + pending_head1 = e; + } + e->prev = pending_tail1; + pending_tail1 = e; + } + + Edge *e0 = min0; + Edge *e1 = min1; + +#ifdef DEBUG_CONVEX_HULL + printf(" Found min edges to %d %d\n", e0 ? e0->target->point.index : -1, e1 ? e1->target->point.index : -1); +#endif + + if (cmp == 0) { + find_edge_for_coplanar_faces(c0, c1, e0, e1, nullptr, nullptr); + } + + if ((cmp >= 0) && e1) { + if (to_prev1) { + for (Edge *e = to_prev1->next, *n = nullptr; e != min1; e = n) { + n = e->next; + remove_edge_pair(e); + } + } + + if (pending_tail1) { + if (to_prev1) { + to_prev1->link(pending_head1); + } else { + min1->prev->link(pending_head1); + first_new1 = pending_head1; + } + pending_tail1->link(min1); + pending_head1 = nullptr; + pending_tail1 = nullptr; + } else if (!to_prev1) { + first_new1 = min1; + } + + prev_point = c1->point; + c1 = e1->target; + to_prev1 = e1->reverse; + } + + if ((cmp <= 0) && e0) { + if (to_prev0) { + for (Edge *e = to_prev0->prev, *n = nullptr; e != min0; e = n) { + n = e->prev; + remove_edge_pair(e); + } + } + + if (pending_tail0) { + if (to_prev0) { + pending_head0->link(to_prev0); + } else { + pending_head0->link(min0->next); + first_new0 = pending_head0; + } + min0->link(pending_tail0); + pending_head0 = nullptr; + pending_tail0 = nullptr; + } else if (!to_prev0) { + first_new0 = min0; + } + + prev_point = c0->point; + c0 = e0->target; + to_prev0 = e0->reverse; + } + } + + if ((c0 == first0) && (c1 == first1)) { + if (to_prev0 == nullptr) { + pending_head0->link(pending_tail0); + c0->edges = pending_tail0; + } else { + for (Edge *e = to_prev0->prev, *n = nullptr; e != first_new0; e = n) { + n = e->prev; + remove_edge_pair(e); + } + if (pending_tail0) { + pending_head0->link(to_prev0); + first_new0->link(pending_tail0); + } + } + + if (to_prev1 == nullptr) { + pending_tail1->link(pending_head1); + c1->edges = pending_tail1; + } else { + for (Edge *e = to_prev1->next, *n = nullptr; e != first_new1; e = n) { + n = e->next; + remove_edge_pair(e); + } + if (pending_tail1) { + to_prev1->link(pending_head1); + pending_tail1->link(first_new1); + } + } + + return; + } + + first_run = false; + } +} + +struct PointComparator { + _FORCE_INLINE_ bool operator()(const ConvexHullInternal::Point32 &p, const ConvexHullInternal::Point32 &q) const { + return (p.y < q.y) || ((p.y == q.y) && ((p.x < q.x) || ((p.x == q.x) && (p.z < q.z)))); + } +}; + +void ConvexHullInternal::compute(const Vector3 *p_coords, int32_t p_count) { + AABB aabb; + for (int32_t i = 0; i < p_count; i++) { + Vector3 p = p_coords[i]; + if (i == 0) { + aabb.position = p; + } else { + aabb.expand_to(p); + } + } + + Vector3 s = aabb.size; + max_axis = s.max_axis(); + min_axis = s.min_axis(); + if (min_axis == max_axis) { + min_axis = (max_axis + 1) % 3; + } + med_axis = 3 - max_axis - min_axis; + + s /= real_t(10216); + if (((med_axis + 1) % 3) != max_axis) { + s *= -1; + } + scaling = s; + + if (s[0] != 0) { + s[0] = real_t(1) / s[0]; + } + if (s[1] != 0) { + s[1] = real_t(1) / s[1]; + } + if (s[2] != 0) { + s[2] = real_t(1) / s[2]; + } + + center = aabb.position; + + LocalVector<Point32> points; + points.resize(p_count); + for (int32_t i = 0; i < p_count; i++) { + Vector3 p = p_coords[i]; + p = (p - center) * s; + points[i].x = (int32_t)p[med_axis]; + points[i].y = (int32_t)p[max_axis]; + points[i].z = (int32_t)p[min_axis]; + points[i].index = i; + } + + points.sort_custom<PointComparator>(); + + vertex_pool.reset(true); + original_vertices.resize(p_count); + for (int32_t i = 0; i < p_count; i++) { + Vertex *v = vertex_pool.alloc(); + v->edges = nullptr; + v->point = points[i]; + v->copy = -1; + original_vertices[i] = v; + } + + points.clear(); + + edge_pool.reset(true); + + used_edge_pairs = 0; + max_used_edge_pairs = 0; + + merge_stamp = -3; + + IntermediateHull hull; + compute_internal(0, p_count, hull); + vertex_list = hull.min_xy; +#ifdef DEBUG_CONVEX_HULL + printf("max. edges %d (3v = %d)", max_used_edge_pairs, 3 * p_count); +#endif +} + +Vector3 ConvexHullInternal::to_gd_vector(const Point32 &p_v) { + Vector3 p; + p[med_axis] = real_t(p_v.x); + p[max_axis] = real_t(p_v.y); + p[min_axis] = real_t(p_v.z); + return p * scaling; +} + +Vector3 ConvexHullInternal::get_gd_normal(Face *p_face) { + return to_gd_vector(p_face->dir0).cross(to_gd_vector(p_face->dir1)).normalized(); +} + +Vector3 ConvexHullInternal::get_coordinates(const Vertex *p_v) { + Vector3 p; + p[med_axis] = p_v->xvalue(); + p[max_axis] = p_v->yvalue(); + p[min_axis] = p_v->zvalue(); + return p * scaling + center; +} + +real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) { + if (!vertex_list) { + return 0; + } + int32_t stamp = --merge_stamp; + LocalVector<Vertex *> stack; + vertex_list->copy = stamp; + stack.push_back(vertex_list); + LocalVector<Face *> faces; + + Point32 ref = vertex_list->point; + Int128 hull_center_x(0, 0); + Int128 hull_center_y(0, 0); + Int128 hull_center_z(0, 0); + Int128 volume(0, 0); + + while (stack.size() > 0) { + Vertex *v = stack[stack.size() - 1]; + stack.remove(stack.size() - 1); + Edge *e = v->edges; + if (e) { + do { + if (e->target->copy != stamp) { + e->target->copy = stamp; + stack.push_back(e->target); + } + if (e->copy != stamp) { + Face *face = face_pool.alloc(); + face->init(e->target, e->reverse->prev->target, v); + faces.push_back(face); + Edge *f = e; + + Vertex *a = nullptr; + Vertex *b = nullptr; + do { + if (a && b) { + int64_t vol = (v->point - ref).dot((a->point - ref).cross(b->point - ref)); + CHULL_ASSERT(vol >= 0); + Point32 c = v->point + a->point + b->point + ref; + hull_center_x += vol * c.x; + hull_center_y += vol * c.y; + hull_center_z += vol * c.z; + volume += vol; + } + + CHULL_ASSERT(f->copy != stamp); + f->copy = stamp; + f->face = face; + + a = b; + b = f->target; + + f = f->reverse->prev; + } while (f != e); + } + e = e->next; + } while (e != v->edges); + } + } + + if (volume.get_sign() <= 0) { + return 0; + } + + Vector3 hull_center; + hull_center[med_axis] = hull_center_x.to_scalar(); + hull_center[max_axis] = hull_center_y.to_scalar(); + hull_center[min_axis] = hull_center_z.to_scalar(); + hull_center /= 4 * volume.to_scalar(); + hull_center *= scaling; + + int32_t face_count = faces.size(); + + if (p_clamp_amount > 0) { + real_t min_dist = FLT_MAX; + for (int32_t i = 0; i < face_count; i++) { + Vector3 normal = get_gd_normal(faces[i]); + real_t dist = normal.dot(to_gd_vector(faces[i]->origin) - hull_center); + if (dist < min_dist) { + min_dist = dist; + } + } + + if (min_dist <= 0) { + return 0; + } + + p_amount = MIN(p_amount, min_dist * p_clamp_amount); + } + + uint32_t seed = 243703; + for (int32_t i = 0; i < face_count; i++, seed = 1664525 * seed + 1013904223) { + SWAP(faces[i], faces[seed % face_count]); + } + + for (int32_t i = 0; i < face_count; i++) { + if (!shift_face(faces[i], p_amount, stack)) { + return -p_amount; + } + } + + return p_amount; +} + +bool ConvexHullInternal::shift_face(Face *p_face, real_t p_amount, LocalVector<Vertex *> p_stack) { + Vector3 orig_shift = get_gd_normal(p_face) * -p_amount; + if (scaling[0] != 0) { + orig_shift[0] /= scaling[0]; + } + if (scaling[1] != 0) { + orig_shift[1] /= scaling[1]; + } + if (scaling[2] != 0) { + orig_shift[2] /= scaling[2]; + } + Point32 shift((int32_t)orig_shift[med_axis], (int32_t)orig_shift[max_axis], (int32_t)orig_shift[min_axis]); + if (shift.is_zero()) { + return true; + } + Point64 normal = p_face->get_normal(); +#ifdef DEBUG_CONVEX_HULL + printf("\nShrinking p_face (%d %d %d) (%d %d %d) (%d %d %d) by (%d %d %d)\n", + p_face->origin.x, p_face->origin.y, p_face->origin.z, p_face->dir0.x, p_face->dir0.y, p_face->dir0.z, p_face->dir1.x, p_face->dir1.y, p_face->dir1.z, shift.x, shift.y, shift.z); +#endif + int64_t orig_dot = p_face->origin.dot(normal); + Point32 shifted_origin = p_face->origin + shift; + int64_t shifted_dot = shifted_origin.dot(normal); + CHULL_ASSERT(shifted_dot <= orig_dot); + if (shifted_dot >= orig_dot) { + return false; + } + + Edge *intersection = nullptr; + + Edge *start_edge = p_face->nearby_vertex->edges; +#ifdef DEBUG_CONVEX_HULL + printf("Start edge is "); + start_edge->print(); + printf(", normal is (%lld %lld %lld), shifted dot is %lld\n", normal.x, normal.y, normal.z, shifted_dot); +#endif + Rational128 opt_dot = p_face->nearby_vertex->dot(normal); + int32_t cmp = opt_dot.compare(shifted_dot); +#ifdef SHOW_ITERATIONS + int32_t n = 0; +#endif + if (cmp >= 0) { + Edge *e = start_edge; + do { +#ifdef SHOW_ITERATIONS + n++; +#endif + Rational128 dot = e->target->dot(normal); + CHULL_ASSERT(dot.compare(orig_dot) <= 0); +#ifdef DEBUG_CONVEX_HULL + printf("Moving downwards, edge is "); + e->print(); + printf(", dot is %f (%f %lld)\n", (float)dot.to_scalar(), (float)opt_dot.to_scalar(), shifted_dot); +#endif + if (dot.compare(opt_dot) < 0) { + int32_t c = dot.compare(shifted_dot); + opt_dot = dot; + e = e->reverse; + start_edge = e; + if (c < 0) { + intersection = e; + break; + } + cmp = c; + } + e = e->prev; + } while (e != start_edge); + + if (!intersection) { + return false; + } + } else { + Edge *e = start_edge; + do { +#ifdef SHOW_ITERATIONS + n++; +#endif + Rational128 dot = e->target->dot(normal); + CHULL_ASSERT(dot.compare(orig_dot) <= 0); +#ifdef DEBUG_CONVEX_HULL + printf("Moving upwards, edge is "); + e->print(); + printf(", dot is %f (%f %lld)\n", (float)dot.to_scalar(), (float)opt_dot.to_scalar(), shifted_dot); +#endif + if (dot.compare(opt_dot) > 0) { + cmp = dot.compare(shifted_dot); + if (cmp >= 0) { + intersection = e; + break; + } + opt_dot = dot; + e = e->reverse; + start_edge = e; + } + e = e->prev; + } while (e != start_edge); + + if (!intersection) { + return true; + } + } + +#ifdef SHOW_ITERATIONS + printf("Needed %d iterations to find initial intersection\n", n); +#endif + + if (cmp == 0) { + Edge *e = intersection->reverse->next; +#ifdef SHOW_ITERATIONS + n = 0; +#endif + while (e->target->dot(normal).compare(shifted_dot) <= 0) { +#ifdef SHOW_ITERATIONS + n++; +#endif + e = e->next; + if (e == intersection->reverse) { + return true; + } +#ifdef DEBUG_CONVEX_HULL + printf("Checking for outwards edge, current edge is "); + e->print(); + printf("\n"); +#endif + } +#ifdef SHOW_ITERATIONS + printf("Needed %d iterations to check for complete containment\n", n); +#endif + } + + Edge *first_intersection = nullptr; + Edge *face_edge = nullptr; + Edge *first_face_edge = nullptr; + +#ifdef SHOW_ITERATIONS + int32_t m = 0; +#endif + while (true) { +#ifdef SHOW_ITERATIONS + m++; +#endif +#ifdef DEBUG_CONVEX_HULL + printf("Intersecting edge is "); + intersection->print(); + printf("\n"); +#endif + if (cmp == 0) { + Edge *e = intersection->reverse->next; + start_edge = e; +#ifdef SHOW_ITERATIONS + n = 0; +#endif + while (true) { +#ifdef SHOW_ITERATIONS + n++; +#endif + if (e->target->dot(normal).compare(shifted_dot) >= 0) { + break; + } + intersection = e->reverse; + e = e->next; + if (e == start_edge) { + return true; + } + } +#ifdef SHOW_ITERATIONS + printf("Needed %d iterations to advance intersection\n", n); +#endif + } + +#ifdef DEBUG_CONVEX_HULL + printf("Advanced intersecting edge to "); + intersection->print(); + printf(", cmp = %d\n", cmp); +#endif + + if (!first_intersection) { + first_intersection = intersection; + } else if (intersection == first_intersection) { + break; + } + + int32_t prev_cmp = cmp; + Edge *prev_intersection = intersection; + Edge *prev_face_edge = face_edge; + + Edge *e = intersection->reverse; +#ifdef SHOW_ITERATIONS + n = 0; +#endif + while (true) { +#ifdef SHOW_ITERATIONS + n++; +#endif + e = e->reverse->prev; + CHULL_ASSERT(e != intersection->reverse); + cmp = e->target->dot(normal).compare(shifted_dot); +#ifdef DEBUG_CONVEX_HULL + printf("Testing edge "); + e->print(); + printf(" -> cmp = %d\n", cmp); +#endif + if (cmp >= 0) { + intersection = e; + break; + } + } +#ifdef SHOW_ITERATIONS + printf("Needed %d iterations to find other intersection of p_face\n", n); +#endif + + if (cmp > 0) { + Vertex *removed = intersection->target; + e = intersection->reverse; + if (e->prev == e) { + removed->edges = nullptr; + } else { + removed->edges = e->prev; + e->prev->link(e->next); + e->link(e); + } +#ifdef DEBUG_CONVEX_HULL + printf("1: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z); +#endif + + Point64 n0 = intersection->face->get_normal(); + Point64 n1 = intersection->reverse->face->get_normal(); + int64_t m00 = p_face->dir0.dot(n0); + int64_t m01 = p_face->dir1.dot(n0); + int64_t m10 = p_face->dir0.dot(n1); + int64_t m11 = p_face->dir1.dot(n1); + int64_t r0 = (intersection->face->origin - shifted_origin).dot(n0); + int64_t r1 = (intersection->reverse->face->origin - shifted_origin).dot(n1); + Int128 det = Int128::mul(m00, m11) - Int128::mul(m01, m10); + CHULL_ASSERT(det.get_sign() != 0); + Vertex *v = vertex_pool.alloc(); + v->point.index = -1; + v->copy = -1; + v->point128 = PointR128(Int128::mul(p_face->dir0.x * r0, m11) - Int128::mul(p_face->dir0.x * r1, m01) + Int128::mul(p_face->dir1.x * r1, m00) - Int128::mul(p_face->dir1.x * r0, m10) + det * shifted_origin.x, + Int128::mul(p_face->dir0.y * r0, m11) - Int128::mul(p_face->dir0.y * r1, m01) + Int128::mul(p_face->dir1.y * r1, m00) - Int128::mul(p_face->dir1.y * r0, m10) + det * shifted_origin.y, + Int128::mul(p_face->dir0.z * r0, m11) - Int128::mul(p_face->dir0.z * r1, m01) + Int128::mul(p_face->dir1.z * r1, m00) - Int128::mul(p_face->dir1.z * r0, m10) + det * shifted_origin.z, + det); + v->point.x = (int32_t)v->point128.xvalue(); + v->point.y = (int32_t)v->point128.yvalue(); + v->point.z = (int32_t)v->point128.zvalue(); + intersection->target = v; + v->edges = e; + + p_stack.push_back(v); + p_stack.push_back(removed); + p_stack.push_back(nullptr); + } + + if (cmp || prev_cmp || (prev_intersection->reverse->next->target != intersection->target)) { + face_edge = new_edge_pair(prev_intersection->target, intersection->target); + if (prev_cmp == 0) { + face_edge->link(prev_intersection->reverse->next); + } + if ((prev_cmp == 0) || prev_face_edge) { + prev_intersection->reverse->link(face_edge); + } + if (cmp == 0) { + intersection->reverse->prev->link(face_edge->reverse); + } + face_edge->reverse->link(intersection->reverse); + } else { + face_edge = prev_intersection->reverse->next; + } + + if (prev_face_edge) { + if (prev_cmp > 0) { + face_edge->link(prev_face_edge->reverse); + } else if (face_edge != prev_face_edge->reverse) { + p_stack.push_back(prev_face_edge->target); + while (face_edge->next != prev_face_edge->reverse) { + Vertex *removed = face_edge->next->target; + remove_edge_pair(face_edge->next); + p_stack.push_back(removed); +#ifdef DEBUG_CONVEX_HULL + printf("2: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z); +#endif + } + p_stack.push_back(nullptr); + } + } + face_edge->face = p_face; + face_edge->reverse->face = intersection->face; + + if (!first_face_edge) { + first_face_edge = face_edge; + } + } +#ifdef SHOW_ITERATIONS + printf("Needed %d iterations to process all intersections\n", m); +#endif + + if (cmp > 0) { + first_face_edge->reverse->target = face_edge->target; + first_intersection->reverse->link(first_face_edge); + first_face_edge->link(face_edge->reverse); + } else if (first_face_edge != face_edge->reverse) { + p_stack.push_back(face_edge->target); + while (first_face_edge->next != face_edge->reverse) { + Vertex *removed = first_face_edge->next->target; + remove_edge_pair(first_face_edge->next); + p_stack.push_back(removed); +#ifdef DEBUG_CONVEX_HULL + printf("3: Removed part contains (%d %d %d)\n", removed->point.x, removed->point.y, removed->point.z); +#endif + } + p_stack.push_back(nullptr); + } + + CHULL_ASSERT(p_stack.size() > 0); + vertex_list = p_stack[0]; + +#ifdef DEBUG_CONVEX_HULL + printf("Removing part\n"); +#endif +#ifdef SHOW_ITERATIONS + n = 0; +#endif + uint32_t pos = 0; + while (pos < p_stack.size()) { + uint32_t end = p_stack.size(); + while (pos < end) { + Vertex *kept = p_stack[pos++]; +#ifdef DEBUG_CONVEX_HULL + kept->print(); +#endif + bool deeper = false; + Vertex *removed; + while ((removed = p_stack[pos++]) != nullptr) { +#ifdef SHOW_ITERATIONS + n++; +#endif + kept->receive_nearby_faces(removed); + while (removed->edges) { + if (!deeper) { + deeper = true; + p_stack.push_back(kept); + } + p_stack.push_back(removed->edges->target); + remove_edge_pair(removed->edges); + } + } + if (deeper) { + p_stack.push_back(nullptr); + } + } + } +#ifdef SHOW_ITERATIONS + printf("Needed %d iterations to remove part\n", n); +#endif + + p_stack.resize(0); + p_face->origin = shifted_origin; + + return true; +} + +static int32_t get_vertex_copy(ConvexHullInternal::Vertex *p_vertex, LocalVector<ConvexHullInternal::Vertex *> &p_vertices) { + int32_t index = p_vertex->copy; + if (index < 0) { + index = p_vertices.size(); + p_vertex->copy = index; + p_vertices.push_back(p_vertex); +#ifdef DEBUG_CONVEX_HULL + printf("Vertex %d gets index *%d\n", p_vertex->point.index, index); +#endif + } + return index; +} + +real_t ConvexHullComputer::compute(const Vector3 *p_coords, int32_t p_count, real_t p_shrink, real_t p_shrink_clamp) { + if (p_count <= 0) { + vertices.clear(); + edges.clear(); + faces.clear(); + return 0; + } + + ConvexHullInternal hull; + hull.compute(p_coords, p_count); + + real_t shift = 0; + if ((p_shrink > 0) && ((shift = hull.shrink(p_shrink, p_shrink_clamp)) < 0)) { + vertices.clear(); + edges.clear(); + faces.clear(); + return shift; + } + + vertices.resize(0); + edges.resize(0); + faces.resize(0); + + LocalVector<ConvexHullInternal::Vertex *> old_vertices; + get_vertex_copy(hull.vertex_list, old_vertices); + int32_t copied = 0; + while (copied < (int32_t)old_vertices.size()) { + ConvexHullInternal::Vertex *v = old_vertices[copied]; + vertices.push_back(hull.get_coordinates(v)); + ConvexHullInternal::Edge *first_edge = v->edges; + if (first_edge) { + int32_t first_copy = -1; + int32_t prev_copy = -1; + ConvexHullInternal::Edge *e = first_edge; + do { + if (e->copy < 0) { + int32_t s = edges.size(); + edges.push_back(Edge()); + edges.push_back(Edge()); + Edge *c = &edges[s]; + Edge *r = &edges[s + 1]; + e->copy = s; + e->reverse->copy = s + 1; + c->reverse = 1; + r->reverse = -1; + c->target_vertex = get_vertex_copy(e->target, old_vertices); + r->target_vertex = copied; +#ifdef DEBUG_CONVEX_HULL + printf(" CREATE: Vertex *%d has edge to *%d\n", copied, c->get_target_vertex()); +#endif + } + if (prev_copy >= 0) { + edges[e->copy].next = prev_copy - e->copy; + } else { + first_copy = e->copy; + } + prev_copy = e->copy; + e = e->next; + } while (e != first_edge); + edges[first_copy].next = prev_copy - first_copy; + } + copied++; + } + + for (int32_t i = 0; i < copied; i++) { + ConvexHullInternal::Vertex *v = old_vertices[i]; + ConvexHullInternal::Edge *first_edge = v->edges; + if (first_edge) { + ConvexHullInternal::Edge *e = first_edge; + do { + if (e->copy >= 0) { +#ifdef DEBUG_CONVEX_HULL + printf("Vertex *%d has edge to *%d\n", i, edges[e->copy].get_target_vertex()); +#endif + faces.push_back(e->copy); + ConvexHullInternal::Edge *f = e; + do { +#ifdef DEBUG_CONVEX_HULL + printf(" Face *%d\n", edges[f->copy].get_target_vertex()); +#endif + f->copy = -1; + f = f->reverse->prev; + } while (f != e); + } + e = e->next; + } while (e != first_edge); + } + } + + return shift; +} + +Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh) { + r_mesh = Geometry3D::MeshData(); // clear + + if (p_points.size() == 0) { + return FAILED; // matches QuickHull + } + + ConvexHullComputer ch; + ch.compute(p_points.ptr(), p_points.size(), -1.0, -1.0); + + r_mesh.vertices = ch.vertices; + + r_mesh.edges.resize(ch.edges.size()); + for (uint32_t i = 0; i < ch.edges.size(); i++) { + r_mesh.edges.write[i].a = (&ch.edges[i])->get_source_vertex(); + r_mesh.edges.write[i].b = (&ch.edges[i])->get_target_vertex(); + } + + r_mesh.faces.resize(ch.faces.size()); + 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]; + + do { + face.indices.push_back(e->get_target_vertex()); + + e = e->get_next_edge_of_face(); + } while (e != e_start); + + // compute normal + if (face.indices.size() >= 3) { + face.plane = Plane(r_mesh.vertices[face.indices[0]], r_mesh.vertices[face.indices[2]], r_mesh.vertices[face.indices[1]]); + } else { + WARN_PRINT("Too few vertices per face."); + } + } + + return OK; +} diff --git a/core/math/convex_hull.h b/core/math/convex_hull.h new file mode 100644 index 0000000000..ba7be9c5e8 --- /dev/null +++ b/core/math/convex_hull.h @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* convex_hull.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +/* +Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#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" +#include "core/templates/vector.h" + +/// Convex hull implementation based on Preparata and Hong +/// See http://code.google.com/p/bullet/issues/detail?id=275 +/// Ole Kniemeyer, MAXON Computer GmbH +class ConvexHullComputer { +public: + class Edge { + private: + int32_t next = 0; + int32_t reverse = 0; + int32_t target_vertex = 0; + + friend class ConvexHullComputer; + + public: + int32_t get_source_vertex() const { + return (this + reverse)->target_vertex; + } + + int32_t get_target_vertex() const { + return target_vertex; + } + + const Edge *get_next_edge_of_vertex() const // clockwise list of all edges of a vertex + { + return this + next; + } + + const Edge *get_next_edge_of_face() const // counter-clockwise list of all edges of a face + { + return (this + reverse)->get_next_edge_of_vertex(); + } + + const Edge *get_reverse_edge() const { + return this + reverse; + } + }; + + // Vertices of the output hull + Vector<Vector3> vertices; + + // Edges of the output hull + LocalVector<Edge> edges; + + // Faces of the convex hull. Each entry is an index into the "edges" array pointing to an edge of the face. Faces are planar n-gons + LocalVector<int32_t> faces; + + /* + Compute convex hull of "count" vertices stored in "coords". + If "shrink" is positive, the convex hull is shrunken by that amount (each face is moved by "shrink" length units + towards the center along its normal). + If "shrinkClamp" is positive, "shrink" is clamped to not exceed "shrinkClamp * innerRadius", where "innerRadius" + is the minimum distance of a face to the center of the convex hull. + The returned value is the amount by which the hull has been shrunken. If it is negative, the amount was so large + that the resulting convex hull is empty. + The output convex hull can be found in the member variables "vertices", "edges", "faces". + */ + real_t compute(const Vector3 *p_coords, int32_t p_count, real_t p_shrink, real_t p_shrink_clamp); + + static Error convex_hull(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_mesh); +}; + +#endif // CONVEX_HULL_H diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 25cc1125db..6f7209556e 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -31,10 +31,10 @@ #ifndef DELAUNAY_3D_H #define DELAUNAY_3D_H +#include "core/io/file_access.h" #include "core/math/aabb.h" #include "core/math/camera_matrix.h" #include "core/math/vector3.h" -#include "core/os/file_access.h" #include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/oa_hash_map.h" diff --git a/core/math/dynamic_bvh.cpp b/core/math/dynamic_bvh.cpp index 200095d8cb..8e596f0f9d 100644 --- a/core/math/dynamic_bvh.cpp +++ b/core/math/dynamic_bvh.cpp @@ -312,8 +312,11 @@ void DynamicBVH::optimize_incremental(int passes) { if (passes < 0) { passes = total_leaves; } - if (bvh_root && (passes > 0)) { + if (passes > 0) { do { + if (!bvh_root) { + break; + } Node *node = bvh_root; unsigned bit = 0; while (node->is_internal()) { diff --git a/core/math/expression.cpp b/core/math/expression.cpp index f7ac44d321..0146c345f0 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -33,7 +33,7 @@ #include "core/io/marshalls.h" #include "core/math/math_funcs.h" #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" diff --git a/core/math/expression.h b/core/math/expression.h index a6b288ed6e..aecf662d0a 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -31,10 +31,10 @@ #ifndef EXPRESSION_H #define EXPRESSION_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class Expression : public Reference { - GDCLASS(Expression, Reference); +class Expression : public RefCounted { + GDCLASS(Expression, RefCounted); private: struct Input { diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 20c316c322..9af3f868d2 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -230,7 +230,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const { real_t minA, maxA, minB, maxB; p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); - project_range(axis, Transform(), minB, maxB); + project_range(axis, Transform3D(), minB, maxB); if (maxA < minB || maxB < minA) { return false; @@ -244,7 +244,7 @@ Face3::operator String() const { return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2]; } -void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void Face3::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { for (int i = 0; i < 3; i++) { Vector3 v = p_transform.xform(vertex[i]); real_t d = p_normal.dot(v); @@ -259,7 +259,7 @@ void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, } } -void Face3::get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { +void Face3::get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { #define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.98 #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.05 diff --git a/core/math/face3.h b/core/math/face3.h index 2e86b0a904..5091b338ef 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -33,7 +33,7 @@ #include "core/math/aabb.h" #include "core/math/plane.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" class Face3 { @@ -74,8 +74,8 @@ public: ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity - void get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; - void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; + void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; AABB get_aabb() const { AABB aabb(vertex[0], Vector3()); diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp index 0985a727f2..570c57e254 100644 --- a/core/math/math_fieldwise.cpp +++ b/core/math/math_fieldwise.cpp @@ -88,8 +88,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } - case Variant::QUAT: { - SETUP_TYPE(Quat) + case Variant::QUATERNION: { + SETUP_TYPE(Quaternion) /**/ TRY_TRANSFER_FIELD("x", x) else TRY_TRANSFER_FIELD("y", y) @@ -141,8 +141,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } - case Variant::TRANSFORM: { - SETUP_TYPE(Transform) + case Variant::TRANSFORM3D: { + SETUP_TYPE(Transform3D) /**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0]) else TRY_TRANSFER_FIELD("xy", basis.elements[0][1]) diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index c0d7649b65..3389407e72 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -275,8 +275,8 @@ public: static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); } static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); } - static _ALWAYS_INLINE_ double round(double p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } - static _ALWAYS_INLINE_ float round(float p_val) { return (p_val >= 0) ? Math::floor(p_val + 0.5) : -Math::floor(-p_val + 0.5); } + static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); } + static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); } static _ALWAYS_INLINE_ int64_t wrapi(int64_t value, int64_t min, int64_t max) { int64_t range = max - min; @@ -311,20 +311,20 @@ public: static float random(float from, float to); static int random(int from, int to); - static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) { + static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b) { // Check for exact equality first, required to handle "infinity" values. if (a == b) { return true; } // Then check for approximate equality. - real_t tolerance = CMP_EPSILON * abs(a); + float tolerance = CMP_EPSILON * abs(a); if (tolerance < CMP_EPSILON) { tolerance = CMP_EPSILON; } return abs(a - b) < tolerance; } - static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) { + static _ALWAYS_INLINE_ bool is_equal_approx(float a, float b, float tolerance) { // Check for exact equality first, required to handle "infinity" values. if (a == b) { return true; @@ -333,7 +333,33 @@ public: return abs(a - b) < tolerance; } - static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) { + static _ALWAYS_INLINE_ bool is_zero_approx(float s) { + return abs(s) < CMP_EPSILON; + } + + static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b) { + // Check for exact equality first, required to handle "infinity" values. + if (a == b) { + return true; + } + // Then check for approximate equality. + double tolerance = CMP_EPSILON * abs(a); + if (tolerance < CMP_EPSILON) { + tolerance = CMP_EPSILON; + } + return abs(a - b) < tolerance; + } + + static _ALWAYS_INLINE_ bool is_equal_approx(double a, double b, double tolerance) { + // Check for exact equality first, required to handle "infinity" values. + if (a == b) { + return true; + } + // Then check for approximate equality. + return abs(a - b) < tolerance; + } + + static _ALWAYS_INLINE_ bool is_zero_approx(double s) { return abs(s) < CMP_EPSILON; } @@ -358,28 +384,10 @@ public: return u.d; } - //this function should be as fast as possible and rounding mode should not matter + // This function should be as fast as possible and rounding mode should not matter. static _ALWAYS_INLINE_ int fast_ftoi(float a) { - static int b; - -#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0603) || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP // windows 8 phone? - b = (int)((a > 0.0) ? (a + 0.5) : (a - 0.5)); - -#elif defined(_MSC_VER) && _MSC_VER < 1800 - __asm fld a __asm fistp b - /*#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) - // use AT&T inline assembly style, document that - // we use memory as output (=m) and input (m) - __asm__ __volatile__ ( - "flds %1 \n\t" - "fistpl %0 \n\t" - : "=m" (b) - : "m" (a));*/ - -#else - b = lrintf(a); //assuming everything but msvc 2012 or earlier has lrint -#endif - return b; + // Assuming every supported compiler has `lrint()`. + return lrintf(a); } static _ALWAYS_INLINE_ uint32_t halfbits_to_floatbits(uint16_t h) { diff --git a/core/math/plane.cpp b/core/math/plane.cpp index f1d3bbbd54..3c78b55b90 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -175,5 +175,5 @@ bool Plane::is_equal_approx(const Plane &p_plane) const { } Plane::operator String() const { - return normal.operator String() + ", " + rtos(d); + return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]"; } diff --git a/core/math/quat.cpp b/core/math/quaternion.cpp index 6f13e04027..7037db7112 100644 --- a/core/math/quat.cpp +++ b/core/math/quaternion.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.cpp */ +/* quaternion.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "quat.h" +#include "quaternion.h" #include "core/math/basis.h" #include "core/string/print_string.h" @@ -37,7 +37,7 @@ // (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 Quat::get_euler_xyz() const { +Vector3 Quaternion::get_euler_xyz() const { Basis m(*this); return m.get_euler_xyz(); } @@ -46,7 +46,7 @@ Vector3 Quat::get_euler_xyz() const { // (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 Quat::get_euler_yxz() const { +Vector3 Quaternion::get_euler_yxz() const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized."); #endif @@ -54,7 +54,7 @@ Vector3 Quat::get_euler_yxz() const { return m.get_euler_yxz(); } -void Quat::operator*=(const Quat &p_q) { +void Quaternion::operator*=(const Quaternion &p_q) { real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; @@ -64,45 +64,45 @@ void Quat::operator*=(const Quat &p_q) { z = zz; } -Quat Quat::operator*(const Quat &p_q) const { - Quat r = *this; +Quaternion Quaternion::operator*(const Quaternion &p_q) const { + Quaternion r = *this; r *= p_q; return r; } -bool Quat::is_equal_approx(const Quat &p_quat) const { - return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w); +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); } -real_t Quat::length() const { +real_t Quaternion::length() const { return Math::sqrt(length_squared()); } -void Quat::normalize() { +void Quaternion::normalize() { *this /= length(); } -Quat Quat::normalized() const { +Quaternion Quaternion::normalized() const { return *this / length(); } -bool Quat::is_normalized() const { - return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); //use less epsilon +bool Quaternion::is_normalized() const { + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon } -Quat Quat::inverse() const { +Quaternion Quaternion::inverse() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized."); #endif - return Quat(-x, -y, -z, w); + return Quaternion(-x, -y, -z, w); } -Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { +Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - Quat to1; + Quaternion to1; real_t omega, cosom, sinom, scale0, scale1; // calc cosine @@ -137,19 +137,19 @@ Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { scale1 = p_weight; } // calculate final values - return Quat( + return Quaternion( scale0 * x + scale1 * to1.x, scale0 * y + scale1 * to1.y, scale0 * z + scale1 * to1.z, scale0 * w + scale1 * to1.w); } -Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { +Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - const Quat &from = *this; + const Quaternion &from = *this; real_t dot = from.dot(p_to); @@ -162,29 +162,29 @@ Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { newFactor = Math::sin(p_weight * theta) * sinT, invFactor = Math::sin((1.0 - p_weight) * theta) * sinT; - return Quat(invFactor * from.x + newFactor * p_to.x, + return Quaternion(invFactor * from.x + newFactor * p_to.x, invFactor * from.y + newFactor * p_to.y, invFactor * from.z + newFactor * p_to.z, invFactor * from.w + newFactor * p_to.w); } -Quat Quat::cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const { +Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif //the only way to do slerp :| real_t t2 = (1.0 - p_weight) * p_weight * 2; - Quat sp = this->slerp(p_b, p_weight); - Quat sq = p_pre_a.slerpni(p_post_b, p_weight); + Quaternion sp = this->slerp(p_b, p_weight); + Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight); return sp.slerpni(sq, t2); } -Quat::operator String() const { - return String::num(x) + ", " + String::num(y) + ", " + String::num(z) + ", " + String::num(w); +Quaternion::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } -Quat::Quat(const Vector3 &p_axis, real_t p_angle) { +Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); #endif @@ -209,7 +209,7 @@ Quat::Quat(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). -Quat::Quat(const Vector3 &p_euler) { +Quaternion::Quaternion(const Vector3 &p_euler) { real_t half_a1 = p_euler.y * 0.5; real_t half_a2 = p_euler.x * 0.5; real_t half_a3 = p_euler.z * 0.5; diff --git a/core/math/quat.h b/core/math/quaternion.h index 9db914fe52..796214b79e 100644 --- a/core/math/quat.h +++ b/core/math/quaternion.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.h */ +/* quaternion.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// Circular dependency between Vector3 and Basis :/ -#include "core/math/vector3.h" - #ifndef QUAT_H #define QUAT_H #include "core/math/math_defs.h" #include "core/math/math_funcs.h" +#include "core/math/vector3.h" #include "core/string/ustring.h" -class Quat { +class Quaternion { public: union { struct { @@ -57,21 +55,21 @@ public: return components[idx]; } _FORCE_INLINE_ real_t length_squared() const; - bool is_equal_approx(const Quat &p_quat) const; + bool is_equal_approx(const Quaternion &p_quaternion) const; real_t length() const; void normalize(); - Quat normalized() const; + Quaternion normalized() const; bool is_normalized() const; - Quat inverse() const; - _FORCE_INLINE_ real_t dot(const Quat &p_q) const; + Quaternion inverse() const; + _FORCE_INLINE_ real_t dot(const Quaternion &p_q) const; Vector3 get_euler_xyz() const; Vector3 get_euler_yxz() const; Vector3 get_euler() const { return get_euler_yxz(); }; - Quat slerp(const Quat &p_to, const real_t &p_weight) const; - Quat slerpni(const Quat &p_to, const real_t &p_weight) const; - Quat cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const; + Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = 2 * Math::acos(w); @@ -81,11 +79,11 @@ public: r_axis.z = z * r; } - void operator*=(const Quat &p_q); - Quat operator*(const Quat &p_q) const; + void operator*=(const Quaternion &p_q); + Quaternion operator*(const Quaternion &p_q) const; - Quat operator*(const Vector3 &v) const { - return Quat(w * v.x + y * v.z - z * v.y, + Quaternion operator*(const Vector3 &v) const { + return Quaternion(w * v.x + y * v.z - z * v.y, w * v.y + z * v.x - x * v.z, w * v.z + x * v.y - y * v.x, -x * v.x - y * v.y - z * v.z); @@ -104,42 +102,42 @@ public: return inverse().xform(v); } - _FORCE_INLINE_ void operator+=(const Quat &p_q); - _FORCE_INLINE_ void operator-=(const Quat &p_q); + _FORCE_INLINE_ void operator+=(const Quaternion &p_q); + _FORCE_INLINE_ void operator-=(const Quaternion &p_q); _FORCE_INLINE_ void operator*=(const real_t &s); _FORCE_INLINE_ void operator/=(const real_t &s); - _FORCE_INLINE_ Quat operator+(const Quat &q2) const; - _FORCE_INLINE_ Quat operator-(const Quat &q2) const; - _FORCE_INLINE_ Quat operator-() const; - _FORCE_INLINE_ Quat operator*(const real_t &s) const; - _FORCE_INLINE_ Quat operator/(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-() const; + _FORCE_INLINE_ Quaternion operator*(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator/(const real_t &s) const; - _FORCE_INLINE_ bool operator==(const Quat &p_quat) const; - _FORCE_INLINE_ bool operator!=(const Quat &p_quat) const; + _FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const; + _FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const; operator String() const; - _FORCE_INLINE_ Quat() {} + _FORCE_INLINE_ Quaternion() {} - _FORCE_INLINE_ Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + _FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : x(p_x), y(p_y), z(p_z), w(p_w) { } - Quat(const Vector3 &p_axis, real_t p_angle); + Quaternion(const Vector3 &p_axis, real_t p_angle); - Quat(const Vector3 &p_euler); + Quaternion(const Vector3 &p_euler); - Quat(const Quat &p_q) : + Quaternion(const Quaternion &p_q) : x(p_q.x), y(p_q.y), z(p_q.z), w(p_q.w) { } - Quat &operator=(const Quat &p_q) { + Quaternion &operator=(const Quaternion &p_q) { x = p_q.x; y = p_q.y; z = p_q.z; @@ -147,7 +145,7 @@ public: return *this; } - Quat(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); @@ -169,72 +167,72 @@ public: } }; -real_t Quat::dot(const Quat &p_q) const { +real_t Quaternion::dot(const Quaternion &p_q) const { return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w; } -real_t Quat::length_squared() const { +real_t Quaternion::length_squared() const { return dot(*this); } -void Quat::operator+=(const Quat &p_q) { +void Quaternion::operator+=(const Quaternion &p_q) { x += p_q.x; y += p_q.y; z += p_q.z; w += p_q.w; } -void Quat::operator-=(const Quat &p_q) { +void Quaternion::operator-=(const Quaternion &p_q) { x -= p_q.x; y -= p_q.y; z -= p_q.z; w -= p_q.w; } -void Quat::operator*=(const real_t &s) { +void Quaternion::operator*=(const real_t &s) { x *= s; y *= s; z *= s; w *= s; } -void Quat::operator/=(const real_t &s) { +void Quaternion::operator/=(const real_t &s) { *this *= 1.0 / s; } -Quat Quat::operator+(const Quat &q2) const { - const Quat &q1 = *this; - return Quat(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); +Quaternion Quaternion::operator+(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); } -Quat Quat::operator-(const Quat &q2) const { - const Quat &q1 = *this; - return Quat(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); +Quaternion Quaternion::operator-(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); } -Quat Quat::operator-() const { - const Quat &q2 = *this; - return Quat(-q2.x, -q2.y, -q2.z, -q2.w); +Quaternion Quaternion::operator-() const { + const Quaternion &q2 = *this; + return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w); } -Quat Quat::operator*(const real_t &s) const { - return Quat(x * s, y * s, z * s, w * s); +Quaternion Quaternion::operator*(const real_t &s) const { + return Quaternion(x * s, y * s, z * s, w * s); } -Quat Quat::operator/(const real_t &s) const { +Quaternion Quaternion::operator/(const real_t &s) const { return *this * (1.0 / s); } -bool Quat::operator==(const Quat &p_quat) const { - return x == p_quat.x && y == p_quat.y && z == p_quat.z && w == p_quat.w; +bool Quaternion::operator==(const Quaternion &p_quaternion) const { + return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w; } -bool Quat::operator!=(const Quat &p_quat) const { - return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w; +bool Quaternion::operator!=(const Quaternion &p_quaternion) const { + return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w; } -_FORCE_INLINE_ Quat operator*(const real_t &p_real, const Quat &p_quat) { - return p_quat * p_real; +_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) { + return p_quaternion * p_real; } #endif // QUAT_H diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index fe18cc3d41..0d77bfe933 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -112,7 +112,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ } } - //fourth vertex is the one most further away from the plane + //fourth vertex is the one most further away from the plane { real_t maxd = 0; diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h index a396c2b7d7..06cd3999f3 100644 --- a/core/math/random_number_generator.h +++ b/core/math/random_number_generator.h @@ -32,10 +32,10 @@ #define RANDOM_NUMBER_GENERATOR_H #include "core/math/random_pcg.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class RandomNumberGenerator : public Reference { - GDCLASS(RandomNumberGenerator, Reference); +class RandomNumberGenerator : public RefCounted { + GDCLASS(RandomNumberGenerator, RefCounted); protected: RandomPCG randbase; diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index 60c44999f7..f64bf560c8 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -263,3 +263,11 @@ next4: return true; } + +Rect2::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} + +Rect2i::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} diff --git a/core/math/rect2.h b/core/math/rect2.h index 1dc027cf72..ab0b489b4a 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -320,7 +320,7 @@ struct Rect2 { return position + size; } - operator String() const { return String(position) + ", " + String(size); } + operator String() const; Rect2() {} Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : @@ -498,7 +498,7 @@ struct Rect2i { return position + size; } - operator String() const { return String(position) + ", " + String(size); } + operator String() const; operator Rect2() const { return Rect2(position, size); } diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 4a521b96ae..0140f31b8a 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -158,6 +158,13 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]); } +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); + return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle()); + return return_trans; +} + bool Transform2D::operator==(const Transform2D &p_transform) const { for (int i = 0; i < 3; i++) { if (elements[i] != p_transform.elements[i]) { @@ -270,5 +277,7 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t } Transform2D::operator String() const { - return String(String() + elements[0] + ", " + elements[1] + ", " + elements[2]); + return "[X: " + elements[0].operator String() + + ", Y: " + elements[1].operator String() + + ", O: " + elements[2].operator String() + "]"; } diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 327d0f244f..715f013701 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -100,6 +100,8 @@ struct Transform2D { Transform2D orthonormalized() const; bool is_equal_approx(const Transform2D &p_transform) const; + Transform2D looking_at(const Vector2 &p_target) const; + bool operator==(const Transform2D &p_transform) const; bool operator!=(const Transform2D &p_transform) const; diff --git a/core/math/transform.cpp b/core/math/transform_3d.cpp index d4d7ff6d28..a34d998dde 100644 --- a/core/math/transform.cpp +++ b/core/math/transform_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.cpp */ +/* transform_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,54 +28,54 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "transform.h" +#include "transform_3d.h" #include "core/math/math_funcs.h" #include "core/string/print_string.h" -void Transform::affine_invert() { +void Transform3D::affine_invert() { basis.invert(); origin = basis.xform(-origin); } -Transform Transform::affine_inverse() const { - Transform ret = *this; +Transform3D Transform3D::affine_inverse() const { + Transform3D ret = *this; ret.affine_invert(); return ret; } -void Transform::invert() { +void Transform3D::invert() { basis.transpose(); origin = basis.xform(-origin); } -Transform Transform::inverse() const { +Transform3D Transform3D::inverse() const { // FIXME: this function assumes the basis is a rotation matrix, with no scaling. - // Transform::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. - Transform ret = *this; + // Transform3D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. + Transform3D ret = *this; ret.invert(); return ret; } -void Transform::rotate(const Vector3 &p_axis, real_t p_phi) { +void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) { *this = rotated(p_axis, p_phi); } -Transform Transform::rotated(const Vector3 &p_axis, real_t p_phi) const { - return Transform(Basis(p_axis, p_phi), Vector3()) * (*this); +Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const { + return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this); } -void Transform::rotate_basis(const Vector3 &p_axis, real_t p_phi) { +void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) { basis.rotate(p_axis, p_phi); } -Transform Transform::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { - Transform t = *this; +Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { + Transform3D t = *this; t.set_look_at(origin, p_target, p_up); return t; } -void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { #ifdef MATH_CHECKS ERR_FAIL_COND(p_eye == p_target); ERR_FAIL_COND(p_up.length() == 0); @@ -108,105 +108,108 @@ void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const origin = p_eye; } -Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) const { +Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const { /* not sure if very "efficient" but good enough? */ Vector3 src_scale = basis.get_scale(); - Quat src_rot = basis.get_rotation_quat(); + Quaternion src_rot = basis.get_rotation_quaternion(); Vector3 src_loc = origin; Vector3 dst_scale = p_transform.basis.get_scale(); - Quat dst_rot = p_transform.basis.get_rotation_quat(); + Quaternion dst_rot = p_transform.basis.get_rotation_quaternion(); Vector3 dst_loc = p_transform.origin; - Transform interp; - interp.basis.set_quat_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); + Transform3D interp; + interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); interp.origin = src_loc.lerp(dst_loc, p_c); return interp; } -void Transform::scale(const Vector3 &p_scale) { +void Transform3D::scale(const Vector3 &p_scale) { basis.scale(p_scale); origin *= p_scale; } -Transform Transform::scaled(const Vector3 &p_scale) const { - Transform t = *this; +Transform3D Transform3D::scaled(const Vector3 &p_scale) const { + Transform3D t = *this; t.scale(p_scale); return t; } -void Transform::scale_basis(const Vector3 &p_scale) { +void Transform3D::scale_basis(const Vector3 &p_scale) { basis.scale(p_scale); } -void Transform::translate(real_t p_tx, real_t p_ty, real_t p_tz) { +void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) { translate(Vector3(p_tx, p_ty, p_tz)); } -void Transform::translate(const Vector3 &p_translation) { +void Transform3D::translate(const Vector3 &p_translation) { for (int i = 0; i < 3; i++) { origin[i] += basis[i].dot(p_translation); } } -Transform Transform::translated(const Vector3 &p_translation) const { - Transform t = *this; +Transform3D Transform3D::translated(const Vector3 &p_translation) const { + Transform3D t = *this; t.translate(p_translation); return t; } -void Transform::orthonormalize() { +void Transform3D::orthonormalize() { basis.orthonormalize(); } -Transform Transform::orthonormalized() const { - Transform _copy = *this; +Transform3D Transform3D::orthonormalized() const { + Transform3D _copy = *this; _copy.orthonormalize(); return _copy; } -bool Transform::is_equal_approx(const Transform &p_transform) const { +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 Transform::operator==(const Transform &p_transform) const { +bool Transform3D::operator==(const Transform3D &p_transform) const { return (basis == p_transform.basis && origin == p_transform.origin); } -bool Transform::operator!=(const Transform &p_transform) const { +bool Transform3D::operator!=(const Transform3D &p_transform) const { return (basis != p_transform.basis || origin != p_transform.origin); } -void Transform::operator*=(const Transform &p_transform) { +void Transform3D::operator*=(const Transform3D &p_transform) { origin = xform(p_transform.origin); basis *= p_transform.basis; } -Transform Transform::operator*(const Transform &p_transform) const { - Transform t = *this; +Transform3D Transform3D::operator*(const Transform3D &p_transform) const { + Transform3D t = *this; t *= p_transform; return t; } -Transform::operator String() const { - return basis.operator String() + " - " + origin.operator String(); +Transform3D::operator String() const { + return "[X: " + basis.get_axis(0).operator String() + + ", Y: " + basis.get_axis(1).operator String() + + ", Z: " + basis.get_axis(2).operator String() + + ", O: " + origin.operator String() + "]"; } -Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) : +Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : basis(p_basis), origin(p_origin) { } -Transform::Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : +Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : origin(p_origin) { basis.set_axis(0, p_x); basis.set_axis(1, p_y); basis.set_axis(2, p_z); } -Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { +Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz); origin = Vector3(ox, oy, oz); } diff --git a/core/math/transform.h b/core/math/transform_3d.h index 1c05dbe554..078a2ca11a 100644 --- a/core/math/transform.h +++ b/core/math/transform_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.h */ +/* transform_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -35,31 +35,31 @@ #include "core/math/basis.h" #include "core/math/plane.h" -class Transform { +class Transform3D { public: Basis basis; Vector3 origin; void invert(); - Transform inverse() const; + Transform3D inverse() const; void affine_invert(); - Transform affine_inverse() const; + Transform3D affine_inverse() const; - Transform rotated(const Vector3 &p_axis, real_t p_phi) const; + Transform3D rotated(const Vector3 &p_axis, real_t p_phi) const; void rotate(const Vector3 &p_axis, real_t p_phi); void rotate_basis(const Vector3 &p_axis, real_t p_phi); void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); - Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; + Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; void scale(const Vector3 &p_scale); - Transform scaled(const Vector3 &p_scale) const; + Transform3D scaled(const Vector3 &p_scale) const; void scale_basis(const Vector3 &p_scale); void translate(real_t p_tx, real_t p_ty, real_t p_tz); void translate(const Vector3 &p_translation); - Transform translated(const Vector3 &p_translation) const; + Transform3D translated(const Vector3 &p_translation) const; const Basis &get_basis() const { return basis; } void set_basis(const Basis &p_basis) { basis = p_basis; } @@ -68,11 +68,11 @@ public: void set_origin(const Vector3 &p_origin) { origin = p_origin; } void orthonormalize(); - Transform orthonormalized() const; - bool is_equal_approx(const Transform &p_transform) const; + Transform3D orthonormalized() const; + bool is_equal_approx(const Transform3D &p_transform) const; - bool operator==(const Transform &p_transform) const; - bool operator!=(const Transform &p_transform) const; + bool operator==(const Transform3D &p_transform) const; + bool operator!=(const Transform3D &p_transform) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; @@ -86,14 +86,14 @@ public: _FORCE_INLINE_ Vector<Vector3> xform(const Vector<Vector3> &p_array) const; _FORCE_INLINE_ Vector<Vector3> xform_inv(const Vector<Vector3> &p_array) const; - void operator*=(const Transform &p_transform); - Transform operator*(const Transform &p_transform) const; + void operator*=(const Transform3D &p_transform); + Transform3D operator*(const Transform3D &p_transform) const; - Transform interpolate_with(const Transform &p_transform, real_t p_c) const; + Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; - _FORCE_INLINE_ Transform inverse_xform(const Transform &t) const { + _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const { Vector3 v = t.origin - origin; - return Transform(basis.transpose_xform(t.basis), + return Transform3D(basis.transpose_xform(t.basis), basis.xform(v)); } @@ -106,20 +106,20 @@ public: operator String() const; - Transform() {} - Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3()); - Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); - Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); + Transform3D() {} + Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()); + Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); + Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); }; -_FORCE_INLINE_ Vector3 Transform::xform(const Vector3 &p_vector) const { +_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const { return Vector3( basis[0].dot(p_vector) + origin.x, basis[1].dot(p_vector) + origin.y, basis[2].dot(p_vector) + origin.z); } -_FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { +_FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const { Vector3 v = p_vector - origin; return Vector3( @@ -128,7 +128,7 @@ _FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { (basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z)); } -_FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { +_FORCE_INLINE_ Plane Transform3D::xform(const Plane &p_plane) const { Vector3 point = p_plane.normal * p_plane.d; Vector3 point_dir = point + p_plane.normal; point = xform(point); @@ -141,7 +141,7 @@ _FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { return Plane(normal, d); } -_FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { +_FORCE_INLINE_ Plane Transform3D::xform_inv(const Plane &p_plane) const { Vector3 point = p_plane.normal * p_plane.d; Vector3 point_dir = point + p_plane.normal; point = xform_inv(point); @@ -154,7 +154,7 @@ _FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { return Plane(normal, d); } -_FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { +_FORCE_INLINE_ AABB Transform3D::xform(const AABB &p_aabb) const { /* http://dev.theomader.com/transform-bounding-boxes/ */ Vector3 min = p_aabb.position; Vector3 max = p_aabb.position + p_aabb.size; @@ -179,7 +179,7 @@ _FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { return r_aabb; } -_FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { +_FORCE_INLINE_ AABB Transform3D::xform_inv(const AABB &p_aabb) const { /* define vertices */ Vector3 vertices[8] = { Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z), @@ -203,7 +203,7 @@ _FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { return ret; } -Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const { +Vector<Vector3> Transform3D::xform(const Vector<Vector3> &p_array) const { Vector<Vector3> array; array.resize(p_array.size()); @@ -216,7 +216,7 @@ Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const { return array; } -Vector<Vector3> Transform::xform_inv(const Vector<Vector3> &p_array) const { +Vector<Vector3> Transform3D::xform_inv(const Vector<Vector3> &p_array) const { Vector<Vector3> array; array.resize(p_array.size()); diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 23c0c686a2..903d5951a8 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -600,7 +600,7 @@ bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *vertexptr = vertices.ptr(); const BVH *bvhptr = bvh.ptr(); - Transform scale(Basis().scaled(p_scale)); + Transform3D scale(Basis().scaled(p_scale)); int pos = bvh.size() - 1; diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 1d1dbc114b..463b0dd5c8 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -32,10 +32,10 @@ #define TRIANGLE_MESH_H #include "core/math/face3.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class TriangleMesh : public Reference { - GDCLASS(TriangleMesh, Reference); +class TriangleMesh : public RefCounted { + GDCLASS(TriangleMesh, RefCounted); struct Triangle { Vector3 normal; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 5129ed336e..eb3301f5d0 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -59,7 +59,7 @@ Vector2 Vector2::normalized() const { bool Vector2::is_normalized() const { // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); } real_t Vector2::distance_to(const Vector2 &p_vector2) const { @@ -122,14 +122,20 @@ Vector2 Vector2::project(const Vector2 &p_to) const { return p_to * (dot(p_to) / p_to.length_squared()); } +Vector2 Vector2::clamp(const Vector2 &p_min, const Vector2 &p_max) const { + return Vector2( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y)); +} + Vector2 Vector2::snapped(const Vector2 &p_step) const { return Vector2( Math::snapped(x, p_step.x), Math::snapped(y, p_step.y)); } -Vector2 Vector2::clamped(real_t p_len) const { - real_t l = length(); +Vector2 Vector2::limit_length(const real_t p_len) const { + const real_t l = length(); Vector2 v = *this; if (l > 0 && p_len < l) { v /= l; @@ -187,8 +193,18 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); } +Vector2::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")"; +} + /* Vector2i */ +Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const { + return Vector2i( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y)); +} + Vector2i Vector2i::operator+(const Vector2i &p_v) const { return Vector2i(x + p_v.x, y + p_v.y); } @@ -257,3 +273,7 @@ bool Vector2i::operator==(const Vector2i &p_vec2) const { bool Vector2i::operator!=(const Vector2i &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } + +Vector2i::operator String() const { + return "(" + itos(x) + ", " + itos(y) + ")"; +} diff --git a/core/math/vector2.h b/core/math/vector2.h index 6abe0f5ea9..78deb473b4 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -84,6 +84,7 @@ struct Vector2 { real_t length() const; real_t length_squared() const; + Vector2 limit_length(const real_t p_len = 1.0) const; Vector2 min(const Vector2 &p_vector2) const { return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y)); @@ -107,8 +108,6 @@ struct Vector2 { Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; - Vector2 clamped(real_t p_len) const; - _FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, real_t p_weight) const; _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, real_t p_weight) const; Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const; @@ -163,9 +162,10 @@ struct Vector2 { Vector2 ceil() const; Vector2 round() const; Vector2 snapped(const Vector2 &p_by) const; + Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const; real_t aspect() const { return width / height; } - operator String() const { return String::num(x) + ", " + String::num(y); } + operator String() const; _FORCE_INLINE_ Vector2() {} _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { @@ -338,8 +338,9 @@ struct Vector2i { real_t aspect() const { return width / (real_t)height; } Vector2i sign() const { return Vector2i(SGN(x), SGN(y)); } Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } + Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; - operator String() const { return String::num(x) + ", " + String::num(y); } + operator String() const; operator Vector2() const { return Vector2(x, y); } diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index d4317d506c..3d59064af6 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -52,6 +52,13 @@ real_t Vector3::get_axis(int p_axis) const { 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), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z)); +} + void Vector3::snap(Vector3 p_step) { x = Math::snapped(x, p_step.x); y = Math::snapped(y, p_step.y); @@ -64,6 +71,17 @@ Vector3 Vector3::snapped(Vector3 p_step) const { return v; } +Vector3 Vector3::limit_length(const real_t p_len) const { + const real_t l = length(); + Vector3 v = *this; + if (l > 0 && p_len < l) { + v /= l; + v *= p_len; + } + + return v; +} + Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const { Vector3 p0 = p_pre_a; Vector3 p1 = *this; @@ -108,5 +126,5 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const { } Vector3::operator String() const { - return (rtos(x) + ", " + rtos(y) + ", " + rtos(z)); + 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 b47c3cc916..d8d3cd3cc0 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -86,6 +86,7 @@ struct Vector3 { _FORCE_INLINE_ Vector3 normalized() const; _FORCE_INLINE_ bool is_normalized() const; _FORCE_INLINE_ Vector3 inverse() const; + Vector3 limit_length(const real_t p_len = 1.0) const; _FORCE_INLINE_ void zero(); @@ -112,6 +113,7 @@ struct Vector3 { _FORCE_INLINE_ Vector3 sign() const; _FORCE_INLINE_ Vector3 ceil() const; _FORCE_INLINE_ Vector3 round() const; + Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const; _FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const; _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const; @@ -423,7 +425,7 @@ Vector3 Vector3::normalized() const { bool Vector3::is_normalized() const { // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. - return Math::is_equal_approx(length_squared(), 1.0, UNIT_EPSILON); + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); } Vector3 Vector3::inverse() const { diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp index 167fa3221d..2de1e4e331 100644 --- a/core/math/vector3i.cpp +++ b/core/math/vector3i.cpp @@ -48,6 +48,13 @@ int Vector3i::max_axis() const { return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0); } +Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { + return Vector3i( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z)); +} + Vector3i::operator String() const { - return (itos(x) + ", " + itos(y) + ", " + itos(z)); + return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; } diff --git a/core/math/vector3i.h b/core/math/vector3i.h index b0411fb62e..37c7c1c368 100644 --- a/core/math/vector3i.h +++ b/core/math/vector3i.h @@ -69,6 +69,7 @@ struct Vector3i { _FORCE_INLINE_ Vector3i abs() const; _FORCE_INLINE_ Vector3i sign() const; + Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const; /* Operators */ diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index fb7eb42738..5bf874ccae 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -501,12 +501,27 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam compat_classes[p_class] = p_fallback; } +thread_local bool initializing_with_extension = false; +thread_local ObjectNativeExtension *initializing_extension = nullptr; +thread_local void *initializing_extension_instance = nullptr; + +void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance) { + if (initializing_with_extension) { + *r_extension = initializing_extension; + *r_extension_instance = initializing_extension_instance; + initializing_with_extension = false; + } else { + *r_extension = nullptr; + *r_extension_instance = nullptr; + } +} + Object *ClassDB::instance(const StringName &p_class) { ClassInfo *ti; { OBJTYPE_RLOCK; ti = classes.getptr(p_class); - if (!ti || ti->disabled || !ti->creation_func) { + if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) { if (compat_classes.has(p_class)) { ti = classes.getptr(compat_classes[p_class]); } @@ -521,6 +536,11 @@ Object *ClassDB::instance(const StringName &p_class) { return nullptr; } #endif + if (ti->native_extension) { + initializing_with_extension = true; + initializing_extension = ti->native_extension; + initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->create_instance_userdata); + } return ti->creation_func(); } @@ -534,7 +554,7 @@ bool ClassDB::can_instance(const StringName &p_class) { return false; } #endif - return (!ti->disabled && ti->creation_func != nullptr); + return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance)); } void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { @@ -1310,6 +1330,24 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe return false; } +void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) { + ClassInfo *type = classes.getptr(p_class); + if (!type) { + ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'."); + } + + if (type->method_map.has(p_method->get_name())) { + // overloading not supported + ERR_FAIL_MSG("Method already bound '" + p_class + "::" + p_method->get_name() + "'."); + } + +#ifdef DEBUG_METHODS_ENABLED + type->method_order.push_back(p_method->get_name()); +#endif + + type->method_map[p_method->get_name()] = p_method; +} + #ifdef DEBUG_METHODS_ENABLED MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname = method_name.name; @@ -1545,6 +1583,26 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con return var; } +void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) { + GLOBAL_LOCK_FUNCTION; + + ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name)); + ERR_FAIL_COND_MSG(classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name)); + + ClassInfo *parent = classes.getptr(p_extension->parent_class_name); + + ClassInfo c; + 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.inherits = parent->name; + c.class_ptr = parent->class_ptr; + c.inherits_ptr = parent; + + classes[p_extension->class_name] = c; +} + RWLock ClassDB::lock; void ClassDB::cleanup_defaults() { diff --git a/core/object/class_db.h b/core/object/class_db.h index 6fd5748dbb..4355c9b0ea 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -97,6 +97,8 @@ public: enum APIType { API_CORE, API_EDITOR, + API_EXTENSION, + API_EDITOR_EXTENSION, API_NONE }; @@ -115,6 +117,8 @@ public: ClassInfo *inherits_ptr = nullptr; void *class_ptr = nullptr; + ObjectNativeExtension *native_extension = nullptr; + HashMap<StringName, MethodBind *> method_map; HashMap<StringName, int> constant_map; HashMap<StringName, List<StringName>> enum_map; @@ -199,6 +203,8 @@ public: //nothing } + static void register_extension_class(ObjectNativeExtension *p_extension); + template <class T> static Object *_create_ptr_func() { return T::create(); @@ -226,6 +232,7 @@ public: static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); static bool can_instance(const StringName &p_class); static Object *instance(const StringName &p_class); + static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, void **r_extension_instance); static APIType get_api_type(const StringName &p_class); static uint64_t get_api_hash(APIType p_api); @@ -334,6 +341,8 @@ public: return bind; } + static void bind_method_custom(const StringName &p_class, MethodBind *p_method); + static void add_signal(StringName p_class, const MethodInfo &p_signal); static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false); static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal); diff --git a/core/object/object.cpp b/core/object/object.cpp index 413f917518..799e63a512 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -385,6 +385,15 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid } } + if (_extension && _extension->set) { + if (_extension->set(_extension_instance, &p_name, &p_value)) { + if (r_valid) { + *r_valid = true; + } + return; + } + } + //try built-in setgetter { if (ClassDB::set_property(this, p_name, p_value, r_valid)) { @@ -451,6 +460,15 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { } } + if (_extension && _extension->get) { + if (_extension->get(_extension_instance, &p_name, &ret)) { + if (r_valid) { + *r_valid = true; + } + return ret; + } + } + //try built-in setgetter { if (ClassDB::get_property(const_cast<Object *>(this), p_name, ret)) { @@ -596,6 +614,17 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons _get_property_listv(p_list, p_reversed); + if (_extension && _extension->get_property_list) { + uint32_t pcount; + const ObjectNativeExtension::PInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount); + for (uint32_t i = 0; i < pcount; i++) { + p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name)); + } + if (_extension->free_property_list) { + _extension->free_property_list(_extension_instance, pinfo); + } + } + if (!is_class("Script")) { // can still be set, but this is for user-friendliness p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT)); } @@ -740,7 +769,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; return Variant(); } - if (Object::cast_to<Reference>(this)) { + if (Object::cast_to<RefCounted>(this)) { r_error.argument = 0; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); @@ -761,6 +790,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a Variant ret; OBJ_DEBUG_LOCK + if (script_instance) { ret = script_instance->call(p_method, p_args, p_argcount, r_error); //force jumptable @@ -778,6 +808,8 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a } } + //extension does not need this, because all methods are registered in MethodBind + MethodBind *method = ClassDB::get_method(get_class_name(), p_method); if (method) { @@ -795,6 +827,10 @@ void Object::notification(int p_notification, bool p_reversed) { if (script_instance) { script_instance->notification(p_notification); } + + if (_extension && _extension->notification) { + _extension->notification(_extension_instance, p_notification); + } } String Object::to_string() { @@ -805,6 +841,9 @@ String Object::to_string() { return ret; } } + if (_extension && _extension->to_string) { + return _extension->to_string(_extension_instance); + } return "[" + get_class() + ":" + itos(get_instance_id()) + "]"; } @@ -1345,7 +1384,7 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) || (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)); - ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. signal: '" + p_signal + "', callable: '" + p_callable + "'."); + ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'."); } ERR_FAIL_COND_MSG(!s, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string())); @@ -1751,6 +1790,8 @@ void Object::_construct_object(bool p_reference) { _instance_id = ObjectDB::add_instance(this); memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); + ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance); + #ifdef DEBUG_ENABLED _lock_index.init(1); #endif @@ -1770,6 +1811,12 @@ Object::~Object() { } script_instance = nullptr; + if (_extension && _extension->free_instance) { + _extension->free_instance(_extension->create_instance_userdata, _extension_instance); + _extension = nullptr; + _extension_instance = nullptr; + } + const StringName *S = nullptr; if (_emitting) { @@ -1853,7 +1900,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max); for (uint32_t i = slot_max; i < new_slot_max; i++) { object_slots[i].object = nullptr; - object_slots[i].is_reference = false; + object_slots[i].is_ref_counted = false; object_slots[i].next_free = i; object_slots[i].validator = 0; } @@ -1866,7 +1913,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID()); } object_slots[slot].object = p_object; - object_slots[slot].is_reference = p_object->is_reference(); + object_slots[slot].is_ref_counted = p_object->is_ref_counted(); validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK; if (unlikely(validator_counter == 0)) { validator_counter = 1; @@ -1877,7 +1924,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { id <<= OBJECTDB_SLOT_MAX_COUNT_BITS; id |= uint64_t(slot); - if (p_object->is_reference()) { + if (p_object->is_ref_counted()) { id |= OBJECTDB_REFERENCE_BIT; } @@ -1915,7 +1962,7 @@ void ObjectDB::remove_instance(Object *p_object) { object_slots[slot_count].next_free = slot; //invalidate, so checks against it fail object_slots[slot].validator = 0; - object_slots[slot].is_reference = false; + object_slots[slot].is_ref_counted = false; object_slots[slot].object = nullptr; spin_lock.unlock(); @@ -1950,7 +1997,7 @@ void ObjectDB::cleanup() { extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); } - uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_reference ? OBJECTDB_REFERENCE_BIT : 0); + uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0); print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); count--; diff --git a/core/object/object.h b/core/object/object.h index 448a33d3bc..37b2e61dfe 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -238,6 +238,50 @@ struct MethodInfo { ////else //return nullptr; +// API used to extend in GDNative and other C compatible compiled languages +class MethodBind; + +struct ObjectNativeExtension { + ObjectNativeExtension *parent = nullptr; + StringName parent_class_name; + StringName class_name; + bool editor_class = false; + bool (*set)(void *instance, const void *name, const void *value) = nullptr; + bool (*get)(void *instance, const void *name, void *ret_variant) = nullptr; + struct PInfo { + uint32_t type; + const char *name; + const char *class_name; + uint32_t hint; + const char *hint_string; + uint32_t usage; + }; + const PInfo *(*get_property_list)(void *instance, uint32_t *count) = nullptr; + void (*free_property_list)(void *instance, const PInfo *) = nullptr; + + //call is not used, as all methods registered in ClassDB + + void (*notification)(void *instance, int32_t what) = nullptr; + const char *(*to_string)(void *instance) = nullptr; + + void (*reference)(void *instance) = nullptr; + void (*unreference)(void *instance) = nullptr; + + _FORCE_INLINE_ bool is_class(const String &p_class) const { + const ObjectNativeExtension *e = this; + while (e) { + if (p_class == e->class_name.operator String()) { + return true; + } + e = e->parent; + } + return false; + } + void *create_instance_userdata = nullptr; + void *(*create_instance)(void *create_instance_userdata) = nullptr; + void (*free_instance)(void *create_instance_userdata, void *instance) = nullptr; +}; + /* the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model. */ @@ -262,9 +306,15 @@ private: \ public: \ virtual String get_class() const override { \ + if (_get_extension()) { \ + return _get_extension()->class_name.operator String(); \ + } \ return String(#m_class); \ } \ virtual const StringName *_get_class_namev() const override { \ + if (_get_extension()) { \ + return &_get_extension()->class_name; \ + } \ if (!_class_name) { \ _class_name = get_class_static(); \ } \ @@ -297,7 +347,12 @@ public: static String inherits_static() { \ return String(#m_inherits); \ } \ - virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \ + virtual bool is_class(const String &p_class) const override { \ + if (_get_extension() && _get_extension()->is_class(p_class)) { \ + return true; \ + } \ + return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \ + } \ virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \ \ static void get_valid_parents_static(List<String> *p_parents) { \ @@ -440,6 +495,9 @@ private: friend bool predelete_handler(Object *); friend void postinitialize_handler(Object *); + ObjectNativeExtension *_extension = nullptr; + void *_extension_instance = nullptr; + struct SignalData { struct Slot { int reference_count = 0; @@ -487,7 +545,7 @@ private: _FORCE_INLINE_ void _construct_object(bool p_reference); - friend class Reference; + friend class RefCounted; bool type_is_reference = false; SafeNumeric<uint32_t> instance_binding_count; void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; @@ -495,6 +553,8 @@ private: Object(bool p_reference); protected: + _ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; } + _ALWAYS_INLINE_ void *_get_extension_instance() const { return _extension_instance; } virtual void _initialize_classv() { initialize_class(); } virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; }; virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; }; @@ -610,13 +670,25 @@ public: static String get_parent_class_static() { return String(); } static String get_category_static() { return String(); } - virtual String get_class() const { return "Object"; } + virtual String get_class() const { + if (_extension) + return _extension->class_name.operator String(); + return "Object"; + } virtual String get_save_class() const { return get_class(); } //class stored when saving - virtual bool is_class(const String &p_class) const { return (p_class == "Object"); } + virtual bool is_class(const String &p_class) const { + if (_extension && _extension->is_class(p_class)) { + return true; + } + return (p_class == "Object"); + } virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; } _FORCE_INLINE_ const StringName &get_class_name() const { + if (_extension) { + return _extension->class_name; + } if (!_class_ptr) { return *_get_class_namev(); } else { @@ -723,7 +795,7 @@ public: void clear_internal_resource_paths(); - _ALWAYS_INLINE_ bool is_reference() const { return type_is_reference; } + _ALWAYS_INLINE_ bool is_ref_counted() const { return type_is_reference; } Object(); virtual ~Object(); @@ -743,7 +815,7 @@ class ObjectDB { struct ObjectSlot { //128 bits per slot uint64_t validator : OBJECTDB_VALIDATOR_BITS; uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS; - uint64_t is_reference : 1; + uint64_t is_ref_counted : 1; Object *object; }; diff --git a/core/object/object_id.h b/core/object/object_id.h index 7f2496ad48..0666ec0855 100644 --- a/core/object/object_id.h +++ b/core/object/object_id.h @@ -42,7 +42,7 @@ class ObjectID { uint64_t id = 0; public: - _ALWAYS_INLINE_ bool is_reference() const { return (id & (uint64_t(1) << 63)) != 0; } + _ALWAYS_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; } _ALWAYS_INLINE_ bool is_valid() const { return id != 0; } _ALWAYS_INLINE_ bool is_null() const { return id == 0; } _ALWAYS_INLINE_ operator uint64_t() const { return id; } diff --git a/core/object/reference.cpp b/core/object/ref_counted.cpp index 22e4e8a336..9862624972 100644 --- a/core/object/reference.cpp +++ b/core/object/ref_counted.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* reference.cpp */ +/* ref_counted.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "reference.h" +#include "ref_counted.h" #include "core/object/script_language.h" -bool Reference::init_ref() { +bool RefCounted::init_ref() { if (reference()) { if (!is_referenced() && refcount_init.unref()) { unreference(); // first referencing is already 1, so compensate for the ref above @@ -44,17 +44,17 @@ bool Reference::init_ref() { } } -void Reference::_bind_methods() { - ClassDB::bind_method(D_METHOD("init_ref"), &Reference::init_ref); - ClassDB::bind_method(D_METHOD("reference"), &Reference::reference); - ClassDB::bind_method(D_METHOD("unreference"), &Reference::unreference); +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); } -int Reference::reference_get_count() const { +int RefCounted::reference_get_count() const { return refcount.get(); } -bool Reference::reference() { +bool RefCounted::reference() { uint32_t rc_val = refcount.refval(); bool success = rc_val != 0; @@ -62,6 +62,9 @@ bool Reference::reference() { if (get_script_instance()) { get_script_instance()->refcount_incremented(); } + if (_get_extension() && _get_extension()->reference) { + _get_extension()->reference(_get_extension_instance()); + } if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { if (_script_instance_bindings[i]) { @@ -74,7 +77,7 @@ bool Reference::reference() { return success; } -bool Reference::unreference() { +bool RefCounted::unreference() { uint32_t rc_val = refcount.unrefval(); bool die = rc_val == 0; @@ -83,6 +86,9 @@ bool Reference::unreference() { bool script_ret = get_script_instance()->refcount_decremented(); die = die && script_ret; } + if (_get_extension() && _get_extension()->unreference) { + _get_extension()->unreference(_get_extension_instance()); + } if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { if (_script_instance_bindings[i]) { @@ -96,7 +102,7 @@ bool Reference::unreference() { return die; } -Reference::Reference() : +RefCounted::RefCounted() : Object(true) { refcount.init(); refcount_init.init(); @@ -111,7 +117,7 @@ Variant WeakRef::get_ref() const { if (!obj) { return Variant(); } - Reference *r = cast_to<Reference>(obj); + RefCounted *r = cast_to<RefCounted>(obj); if (r) { return REF(r); } diff --git a/core/object/reference.h b/core/object/ref_counted.h index d02cb12069..3dd7cc456b 100644 --- a/core/object/reference.h +++ b/core/object/ref_counted.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* reference.h */ +/* ref_counted.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REFERENCE_H -#define REFERENCE_H +#ifndef REF_COUNTED_H +#define REF_COUNTED_H #include "core/object/class_db.h" #include "core/templates/safe_refcount.h" -class Reference : public Object { - GDCLASS(Reference, Object); +class RefCounted : public Object { + GDCLASS(RefCounted, Object); SafeRefCount refcount; SafeRefCount refcount_init; @@ -49,8 +49,8 @@ public: bool unreference(); int reference_get_count() const; - Reference(); - ~Reference() {} + RefCounted(); + ~RefCounted() {} }; template <class T> @@ -78,7 +78,7 @@ class Ref { } } - //virtual Reference * get_reference() const { return reference; } + //virtual RefCounted * get_reference() const { return reference; } public: _FORCE_INLINE_ bool operator==(const T *p_ptr) const { return reference == p_ptr; @@ -130,7 +130,7 @@ public: template <class T_Other> void operator=(const Ref<T_Other> &p_from) { - Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr())); + RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); if (!refb) { unref(); return; @@ -179,7 +179,7 @@ public: template <class T_Other> Ref(const Ref<T_Other> &p_from) { - Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr())); + RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); if (!refb) { unref(); return; @@ -234,10 +234,10 @@ public: } }; -typedef Ref<Reference> REF; +typedef Ref<RefCounted> REF; -class WeakRef : public Reference { - GDCLASS(WeakRef, Reference); +class WeakRef : public RefCounted { + GDCLASS(WeakRef, RefCounted); ObjectID ref; @@ -259,7 +259,7 @@ struct PtrToArg<Ref<T>> { } _FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) { - *(Ref<Reference> *)p_ptr = p_val; + *(Ref<RefCounted> *)p_ptr = p_val; } }; @@ -294,4 +294,4 @@ struct GetTypeInfo<const Ref<T> &> { #endif // DEBUG_METHODS_ENABLED -#endif // REFERENCE_H +#endif // REF_COUNTED_H diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 42fb0a0caf..196f7a1876 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -353,10 +353,10 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const p_core_type_words->push_back("Vector3i"); p_core_type_words->push_back("Transform2D"); p_core_type_words->push_back("Plane"); - p_core_type_words->push_back("Quat"); + p_core_type_words->push_back("Quaternion"); p_core_type_words->push_back("AABB"); p_core_type_words->push_back("Basis"); - p_core_type_words->push_back("Transform"); + p_core_type_words->push_back("Transform3D"); p_core_type_words->push_back("Color"); p_core_type_words->push_back("StringName"); p_core_type_words->push_back("NodePath"); @@ -585,14 +585,6 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam return Variant(); } -uint16_t PlaceHolderScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return UINT16_MAX; -} - -uint16_t PlaceHolderScriptInstance::get_rset_property_id(const StringName &p_method) const { - return UINT16_MAX; -} - PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) : owner(p_owner), language(p_language), diff --git a/core/object/script_language.h b/core/object/script_language.h index bb46c718b2..a22e91870e 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -41,21 +41,6 @@ class ScriptLanguage; typedef void (*ScriptEditRequestFunction)(const String &p_path); -struct ScriptNetData { - StringName name; - MultiplayerAPI::RPCMode mode; - bool operator==(ScriptNetData const &p_other) const { - return name == p_other.name; - } -}; - -struct SortNetData { - StringName::AlphCompare compare; - bool operator()(const ScriptNetData &p_a, const ScriptNetData &p_b) const { - return compare(p_a.name, p_b.name); - } -}; - class ScriptServer { enum { MAX_LANGUAGES = 16 @@ -174,17 +159,7 @@ public: virtual bool is_placeholder_fallback_enabled() const { return false; } - virtual Vector<ScriptNetData> get_rpc_methods() const = 0; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; - - virtual Vector<ScriptNetData> get_rset_properties() const = 0; - virtual uint16_t get_rset_property_id(const StringName &p_property) const = 0; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; Script() {} }; @@ -225,23 +200,15 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); - virtual Vector<ScriptNetData> get_rpc_methods() const = 0; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0; - virtual StringName get_rpc_method(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; - - virtual Vector<ScriptNetData> get_rset_properties() const = 0; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const = 0; - virtual StringName get_rset_property(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); }; struct ScriptCodeCompletionOption { + /* Keep enum in Sync with: */ + /* /scene/gui/code_edit.h - CodeEdit::CodeCompletionKind */ enum Kind { KIND_CLASS, KIND_FUNCTION, @@ -445,17 +412,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr); - virtual Vector<ScriptNetData> get_rpc_methods() const { return Vector<ScriptNetData>(); } - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const { return StringName(); } - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - - virtual Vector<ScriptNetData> get_rset_properties() const { return Vector<ScriptNetData>(); } - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const { return StringName(); } - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; } + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); } PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner); ~PlaceHolderScriptInstance(); diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index e8735e335c..96c96c1efb 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -122,8 +122,8 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_METHOD; @@ -148,8 +148,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_METHOD; @@ -167,8 +167,8 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_PROPERTY; @@ -189,8 +189,8 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_PROPERTY; @@ -205,8 +205,8 @@ void UndoRedo::add_do_reference(Object *p_object) { ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_REFERENCE; @@ -225,8 +225,8 @@ void UndoRedo::add_undo_reference(Object *p_object) { Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_REFERENCE; diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index a08ca7792f..8f009830e3 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -32,7 +32,7 @@ #define UNDO_REDO_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class UndoRedo : public Object { GDCLASS(UndoRedo, Object); @@ -61,7 +61,7 @@ private: }; Type type; - Ref<Reference> ref; + Ref<RefCounted> ref; ObjectID object; StringName name; Variant args[VARIANT_ARG_MAX]; diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp index 4b2cafd8fe..4c5f0b5220 100644 --- a/core/os/keyboard.cpp +++ b/core/os/keyboard.cpp @@ -60,7 +60,7 @@ static const _KeyCodeText _keycodes[] = { {KEY_PAGEUP ,"PageUp"}, {KEY_PAGEDOWN ,"PageDown"}, {KEY_SHIFT ,"Shift"}, - {KEY_CONTROL ,"Control"}, + {KEY_CTRL ,"Ctrl"}, #ifdef OSX_ENABLED {KEY_META ,"Command"}, #else @@ -314,7 +314,7 @@ bool keycode_has_unicode(uint32_t p_keycode) { case KEY_PAGEUP: case KEY_PAGEDOWN: case KEY_SHIFT: - case KEY_CONTROL: + case KEY_CTRL: case KEY_META: case KEY_ALT: case KEY_CAPSLOCK: @@ -401,7 +401,7 @@ String keycode_get_string(uint32_t p_code) { codestr += "+"; } if (p_code & KEY_MASK_CTRL) { - codestr += find_keycode_name(KEY_CONTROL); + codestr += find_keycode_name(KEY_CTRL); codestr += "+"; } if (p_code & KEY_MASK_META) { diff --git a/core/os/keyboard.h b/core/os/keyboard.h index f6fe5fc070..33f9213c4e 100644 --- a/core/os/keyboard.h +++ b/core/os/keyboard.h @@ -68,7 +68,7 @@ enum Key { KEY_PAGEUP = SPKEY | 0x13, KEY_PAGEDOWN = SPKEY | 0x14, KEY_SHIFT = SPKEY | 0x15, - KEY_CONTROL = SPKEY | 0x16, + KEY_CTRL = SPKEY | 0x16, KEY_META = SPKEY | 0x17, KEY_ALT = SPKEY | 0x18, KEY_CAPSLOCK = SPKEY | 0x19, diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 25a09fe98f..34e944709b 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -32,7 +32,7 @@ #define MAIN_LOOP_H #include "core/input/input_event.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" class MainLoop : public Object { diff --git a/core/os/os.cpp b/core/os/os.cpp index ca1b798e11..535eee4797 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -32,8 +32,8 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/midi_driver.h" #include "core/version_generated.gen.h" #include "servers/audio_server.h" @@ -47,37 +47,8 @@ OS *OS::get_singleton() { return singleton; } -uint32_t OS::get_ticks_msec() const { - return get_ticks_usec() / 1000; -} - -String OS::get_iso_date_time(bool local) const { - OS::Date date = get_date(local); - OS::Time time = get_time(local); - - String timezone; - if (!local) { - TimeZoneInfo zone = get_time_zone_info(); - if (zone.bias >= 0) { - timezone = "+"; - } - timezone = timezone + itos(zone.bias / 60).pad_zeros(2) + itos(zone.bias % 60).pad_zeros(2); - } else { - timezone = "Z"; - } - - return itos(date.year).pad_zeros(2) + - "-" + - itos(date.month).pad_zeros(2) + - "-" + - itos(date.day).pad_zeros(2) + - "T" + - itos(time.hour).pad_zeros(2) + - ":" + - itos(time.min).pad_zeros(2) + - ":" + - itos(time.sec).pad_zeros(2) + - timezone; +uint64_t OS::get_ticks_msec() const { + return get_ticks_usec() / 1000ULL; } double OS::get_unix_time() const { @@ -310,6 +281,11 @@ String OS::get_user_data_dir() const { return "."; } +// Android OS path to app's external data storage +String OS::get_external_data_dir() const { + return get_user_data_dir(); +}; + // Absolute path to res:// String OS::get_resource_dir() const { return ProjectSettings::get_singleton()->get_resource_path(); diff --git a/core/os/os.h b/core/os/os.h index 7198607237..444f67431f 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -158,17 +158,17 @@ public: virtual void yield(); - enum Weekday { - DAY_SUNDAY, - DAY_MONDAY, - DAY_TUESDAY, - DAY_WEDNESDAY, - DAY_THURSDAY, - DAY_FRIDAY, - DAY_SATURDAY + enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, }; - enum Month { + enum Month : uint8_t { /// Start at 1 to follow Windows SYSTEMTIME structure /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx MONTH_JANUARY = 1, @@ -182,21 +182,21 @@ public: MONTH_SEPTEMBER, MONTH_OCTOBER, MONTH_NOVEMBER, - MONTH_DECEMBER + MONTH_DECEMBER, }; struct Date { - int year; + int64_t year; Month month; - int day; + uint8_t day; Weekday weekday; bool dst; }; struct Time { - int hour; - int min; - int sec; + uint8_t hour; + uint8_t minute; + uint8_t second; }; struct TimeZoneInfo { @@ -207,14 +207,13 @@ public: virtual Date get_date(bool local = false) const = 0; virtual Time get_time(bool local = false) const = 0; virtual TimeZoneInfo get_time_zone_info() const = 0; - virtual String get_iso_date_time(bool local = false) const; virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; virtual void add_frame_delay(bool p_can_draw); virtual uint64_t get_ticks_usec() const = 0; - uint32_t get_ticks_msec() const; + uint64_t get_ticks_msec() const; virtual bool is_userfs_persistent() const { return true; } @@ -252,6 +251,7 @@ public: virtual String get_bundle_resource_dir() const; virtual String get_user_data_dir() const; + virtual String get_external_data_dir() const; virtual String get_resource_dir() const; enum SystemDir { diff --git a/core/os/time.cpp b/core/os/time.cpp new file mode 100644 index 0000000000..a185029969 --- /dev/null +++ b/core/os/time.cpp @@ -0,0 +1,433 @@ +/*************************************************************************/ +/* time.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "time.h" + +#include "core/os/os.h" + +#define UNIX_EPOCH_YEAR_AD 1970 // 1970 +#define SECONDS_PER_DAY (24 * 60 * 60) // 86400 +#define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) +#define YEAR_SIZE(year) (IS_LEAP_YEAR(year) ? 366 : 365) + +#define YEAR_KEY "year" +#define MONTH_KEY "month" +#define DAY_KEY "day" +#define WEEKDAY_KEY "weekday" +#define HOUR_KEY "hour" +#define MINUTE_KEY "minute" +#define SECOND_KEY "second" +#define DST_KEY "dst" + +// Table of number of days in each month (for regular year and leap year). +static const uint8_t MONTH_DAYS_TABLE[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +VARIANT_ENUM_CAST(Time::Month); +VARIANT_ENUM_CAST(Time::Weekday); + +#define UNIX_TIME_TO_HMS \ + uint8_t hour, minute, second; \ + { \ + /* The time of the day (in seconds since start of day). */ \ + uint32_t day_clock = Math::posmod(p_unix_time_val, SECONDS_PER_DAY); \ + /* On x86 these 4 lines can be optimized to only 2 divisions. */ \ + second = day_clock % 60; \ + day_clock /= 60; \ + minute = day_clock % 60; \ + hour = day_clock / 60; \ + } + +#define UNIX_TIME_TO_YMD \ + int64_t year; \ + Month month; \ + uint8_t day; \ + /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \ + int64_t day_number = Math::floor(p_unix_time_val / (double)SECONDS_PER_DAY); \ + { \ + int64_t day_number_copy = day_number; \ + year = UNIX_EPOCH_YEAR_AD; \ + uint8_t month_zero_index = 0; \ + while (day_number_copy >= YEAR_SIZE(year)) { \ + day_number_copy -= YEAR_SIZE(year); \ + year++; \ + } \ + while (day_number_copy < 0) { \ + year--; \ + day_number_copy += YEAR_SIZE(year); \ + } \ + /* After the above, day_number now represents the day of the year (0-index). */ \ + while (day_number_copy >= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]) { \ + day_number_copy -= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]; \ + month_zero_index++; \ + } \ + /* After the above, day_number now represents the day of the month (0-index). */ \ + month = (Month)(month_zero_index + 1); \ + day = day_number_copy + 1; \ + } + +#define VALIDATE_YMDHMS \ + ERR_FAIL_COND_V_MSG(month == 0, 0, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \ + ERR_FAIL_COND_V_MSG(month > 12, 0, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \ + ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); \ + ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); \ + ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \ + /* Do this check after month is tested as valid. */ \ + ERR_FAIL_COND_V_MSG(day == 0, 0, "Invalid day value of: " + itos(month) + ", days are 1-indexed and cannot be 0."); \ + uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \ + ERR_FAIL_COND_V_MSG(day > days_in_this_month, 0, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + "."); + +#define YMD_TO_DAY_NUMBER \ + /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \ + int64_t day_number = day - 1; \ + /* Add the days in the months to day_number. */ \ + for (int i = 0; i < month - 1; i++) { \ + day_number += MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][i]; \ + } \ + /* Add the days in the years to day_number. */ \ + if (year >= UNIX_EPOCH_YEAR_AD) { \ + for (int64_t iyear = UNIX_EPOCH_YEAR_AD; iyear < year; iyear++) { \ + day_number += YEAR_SIZE(iyear); \ + } \ + } else { \ + for (int64_t iyear = UNIX_EPOCH_YEAR_AD - 1; iyear >= year; iyear--) { \ + day_number -= YEAR_SIZE(iyear); \ + } \ + } + +#define PARSE_ISO8601_STRING \ + int64_t year = UNIX_EPOCH_YEAR_AD; \ + Month month = MONTH_JANUARY; \ + uint8_t day = 1; \ + uint8_t hour = 0; \ + uint8_t minute = 0; \ + uint8_t second = 0; \ + { \ + bool has_date = false, has_time = false; \ + String date, time; \ + if (p_datetime.find_char('T') > 0) { \ + has_date = has_time = true; \ + PackedStringArray array = p_datetime.split("T"); \ + date = array[0]; \ + time = array[1]; \ + } else if (p_datetime.find_char(' ') > 0) { \ + has_date = has_time = true; \ + PackedStringArray array = p_datetime.split(" "); \ + date = array[0]; \ + time = array[1]; \ + } else if (p_datetime.find_char('-', 1) > 0) { \ + has_date = true; \ + date = p_datetime; \ + } else if (p_datetime.find_char(':') > 0) { \ + has_time = true; \ + time = p_datetime; \ + } \ + /* Set the variables from the contents of the string. */ \ + if (has_date) { \ + PackedInt32Array array = date.split_ints("-", false); \ + year = array[0]; \ + month = (Month)array[1]; \ + day = array[2]; \ + /* Handle negative years. */ \ + if (p_datetime.find_char('-') == 0) { \ + year *= -1; \ + } \ + } \ + if (has_time) { \ + PackedInt32Array array = time.split_ints(":", false); \ + hour = array[0]; \ + minute = array[1]; \ + second = array[2]; \ + } \ + } + +#define EXTRACT_FROM_DICTIONARY \ + /* Get all time values from the dictionary. If it doesn't exist, set the */ \ + /* values to the default values for Unix epoch (1970-01-01 00:00:00). */ \ + int64_t year = p_datetime.has(YEAR_KEY) ? int64_t(p_datetime[YEAR_KEY]) : UNIX_EPOCH_YEAR_AD; \ + Month month = Month((p_datetime.has(MONTH_KEY)) ? uint8_t(p_datetime[MONTH_KEY]) : 1); \ + uint8_t day = p_datetime.has(DAY_KEY) ? uint8_t(p_datetime[DAY_KEY]) : 1; \ + uint8_t hour = p_datetime.has(HOUR_KEY) ? uint8_t(p_datetime[HOUR_KEY]) : 0; \ + uint8_t minute = p_datetime.has(MINUTE_KEY) ? uint8_t(p_datetime[MINUTE_KEY]) : 0; \ + uint8_t second = p_datetime.has(SECOND_KEY) ? uint8_t(p_datetime[SECOND_KEY]) : 0; + +Time *Time::singleton = nullptr; + +Time *Time::get_singleton() { + if (!singleton) { + memnew(Time); + } + return singleton; +} + +Dictionary Time::get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + UNIX_TIME_TO_YMD + Dictionary datetime; + datetime[YEAR_KEY] = year; + datetime[MONTH_KEY] = (uint8_t)month; + datetime[DAY_KEY] = day; + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + datetime[HOUR_KEY] = hour; + datetime[MINUTE_KEY] = minute; + datetime[SECOND_KEY] = second; + + return datetime; +} + +Dictionary Time::get_date_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_YMD + Dictionary datetime; + datetime[YEAR_KEY] = year; + datetime[MONTH_KEY] = (uint8_t)month; + datetime[DAY_KEY] = day; + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + + return datetime; +} + +Dictionary Time::get_time_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + Dictionary datetime; + datetime[HOUR_KEY] = hour; + datetime[MINUTE_KEY] = minute; + datetime[SECOND_KEY] = second; + + return datetime; +} + +String Time::get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space) const { + UNIX_TIME_TO_HMS + UNIX_TIME_TO_YMD + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second); + } + + return timestamp; +} + +String Time::get_date_string_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_YMD + // Android is picky about the types passed to make Variant, so we need a cast. + return vformat("%04d-%02d-%02d", year, (uint8_t)month, day); +} + +String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + return vformat("%02d:%02d:%02d", hour, minute, second); +} + +Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const { + PARSE_ISO8601_STRING + Dictionary dict; + dict[YEAR_KEY] = year; + dict[MONTH_KEY] = (uint8_t)month; + dict[DAY_KEY] = day; + if (p_weekday) { + YMD_TO_DAY_NUMBER + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + dict[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + } + dict[HOUR_KEY] = hour; + dict[MINUTE_KEY] = minute; + dict[SECOND_KEY] = second; + + return dict; +} + +String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const { + ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty."); + EXTRACT_FROM_DICTIONARY + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second); + } + return timestamp; +} + +int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const { + ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); + EXTRACT_FROM_DICTIONARY + VALIDATE_YMDHMS + YMD_TO_DAY_NUMBER + return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second; +} + +int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const { + PARSE_ISO8601_STRING + VALIDATE_YMDHMS + YMD_TO_DAY_NUMBER + return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second; +} + +Dictionary Time::get_datetime_dict_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + OS::Time time = OS::get_singleton()->get_time(p_utc); + Dictionary datetime; + datetime[YEAR_KEY] = date.year; + datetime[MONTH_KEY] = (uint8_t)date.month; + datetime[DAY_KEY] = date.day; + datetime[WEEKDAY_KEY] = (uint8_t)date.weekday; + datetime[DST_KEY] = date.dst; + datetime[HOUR_KEY] = time.hour; + datetime[MINUTE_KEY] = time.minute; + datetime[SECOND_KEY] = time.second; + return datetime; +} + +Dictionary Time::get_date_dict_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + Dictionary date_dictionary; + date_dictionary[YEAR_KEY] = date.year; + date_dictionary[MONTH_KEY] = (uint8_t)date.month; + date_dictionary[DAY_KEY] = date.day; + date_dictionary[WEEKDAY_KEY] = (uint8_t)date.weekday; + date_dictionary[DST_KEY] = date.dst; + return date_dictionary; +} + +Dictionary Time::get_time_dict_from_system(bool p_utc) const { + OS::Time time = OS::get_singleton()->get_time(p_utc); + Dictionary time_dictionary; + time_dictionary[HOUR_KEY] = time.hour; + time_dictionary[MINUTE_KEY] = time.minute; + time_dictionary[SECOND_KEY] = time.second; + return time_dictionary; +} + +String Time::get_datetime_string_from_system(bool p_utc, bool p_use_space) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + OS::Time time = OS::get_singleton()->get_time(p_utc); + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, time.hour, time.minute, time.second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, time.hour, time.minute, time.second); + } + + return timestamp; +} + +String Time::get_date_string_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + // Android is picky about the types passed to make Variant, so we need a cast. + return vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day); +} + +String Time::get_time_string_from_system(bool p_utc) const { + OS::Time time = OS::get_singleton()->get_time(p_utc); + return vformat("%02d:%02d:%02d", time.hour, time.minute, time.second); +} + +Dictionary Time::get_time_zone_from_system() const { + OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info(); + Dictionary timezone; + timezone["bias"] = info.bias; + timezone["name"] = info.name; + return timezone; +} + +double Time::get_unix_time_from_system() const { + return OS::get_singleton()->get_unix_time(); +} + +uint64_t Time::get_ticks_msec() const { + return OS::get_singleton()->get_ticks_msec(); +} + +uint64_t Time::get_ticks_usec() const { + return OS::get_singleton()->get_ticks_usec(); +} + +void Time::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_unix_time", "unix_time_val"), &Time::get_datetime_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_date_dict_from_unix_time", "unix_time_val"), &Time::get_date_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_time_dict_from_unix_time", "unix_time_val"), &Time::get_time_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time); + ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time); + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict); + ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict); + ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string); + + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_dict_from_system", "utc"), &Time::get_time_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_system", "utc", "use_space"), &Time::get_datetime_string_from_system, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_string_from_system", "utc"), &Time::get_date_string_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_string_from_system", "utc"), &Time::get_time_string_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_zone_from_system"), &Time::get_time_zone_from_system); + ClassDB::bind_method(D_METHOD("get_unix_time_from_system"), &Time::get_unix_time_from_system); + ClassDB::bind_method(D_METHOD("get_ticks_msec"), &Time::get_ticks_msec); + ClassDB::bind_method(D_METHOD("get_ticks_usec"), &Time::get_ticks_usec); + + BIND_ENUM_CONSTANT(MONTH_JANUARY); + BIND_ENUM_CONSTANT(MONTH_FEBRUARY); + BIND_ENUM_CONSTANT(MONTH_MARCH); + BIND_ENUM_CONSTANT(MONTH_APRIL); + BIND_ENUM_CONSTANT(MONTH_MAY); + BIND_ENUM_CONSTANT(MONTH_JUNE); + BIND_ENUM_CONSTANT(MONTH_JULY); + BIND_ENUM_CONSTANT(MONTH_AUGUST); + BIND_ENUM_CONSTANT(MONTH_SEPTEMBER); + BIND_ENUM_CONSTANT(MONTH_OCTOBER); + BIND_ENUM_CONSTANT(MONTH_NOVEMBER); + BIND_ENUM_CONSTANT(MONTH_DECEMBER); + + BIND_ENUM_CONSTANT(WEEKDAY_SUNDAY); + BIND_ENUM_CONSTANT(WEEKDAY_MONDAY); + BIND_ENUM_CONSTANT(WEEKDAY_TUESDAY); + BIND_ENUM_CONSTANT(WEEKDAY_WEDNESDAY); + BIND_ENUM_CONSTANT(WEEKDAY_THURSDAY); + BIND_ENUM_CONSTANT(WEEKDAY_FRIDAY); + BIND_ENUM_CONSTANT(WEEKDAY_SATURDAY); +} + +Time::Time() { + ERR_FAIL_COND_MSG(singleton, "Singleton for Time already exists."); + singleton = this; +} + +Time::~Time() { + singleton = nullptr; +} diff --git a/core/os/time.h b/core/os/time.h new file mode 100644 index 0000000000..4325f93d56 --- /dev/null +++ b/core/os/time.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* time.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TIME_H +#define TIME_H + +#include "core/object/class_db.h" + +// This Time class conforms with as many of the ISO 8601 standards as possible. +// * As per ISO 8601:2004 4.3.2.1, all dates follow the Proleptic Gregorian +// calendar. As such, the day before 1582-10-15 is 1582-10-14, not 1582-10-04. +// See: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar +// * As per ISO 8601:2004 3.4.2 and 4.1.2.4, the year before 1 AD (aka 1 BC) +// is number "0", with the year before that (2 BC) being "-1", etc. +// Conversion methods assume "the same timezone", and do not handle DST. +// Leap seconds are not handled, they must be done manually if desired. +// Suffixes such as "Z" are not handled, you need to strip them away manually. + +class Time : public Object { + GDCLASS(Time, Object); + static void _bind_methods(); + static Time *singleton; + +public: + static Time *get_singleton(); + + enum Month : uint8_t { + /// Start at 1 to follow Windows SYSTEMTIME structure + /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx + MONTH_JANUARY = 1, + MONTH_FEBRUARY, + MONTH_MARCH, + MONTH_APRIL, + MONTH_MAY, + MONTH_JUNE, + MONTH_JULY, + MONTH_AUGUST, + MONTH_SEPTEMBER, + MONTH_OCTOBER, + MONTH_NOVEMBER, + MONTH_DECEMBER, + }; + + enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, + }; + + // Methods that convert times. + Dictionary get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_date_dict_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_time_dict_from_unix_time(int64_t p_unix_time_val) const; + String get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space = false) const; + String get_date_string_from_unix_time(int64_t p_unix_time_val) const; + String get_time_string_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const; + String get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space = false) const; + int64_t get_unix_time_from_datetime_dict(Dictionary p_datetime) const; + int64_t get_unix_time_from_datetime_string(String p_datetime) const; + + // Methods that get information from OS. + Dictionary get_datetime_dict_from_system(bool p_utc = false) const; + Dictionary get_date_dict_from_system(bool p_utc = false) const; + Dictionary get_time_dict_from_system(bool p_utc = false) const; + String get_datetime_string_from_system(bool p_utc = false, bool p_use_space = false) const; + String get_date_string_from_system(bool p_utc = false) const; + String get_time_string_from_system(bool p_utc = false) const; + Dictionary get_time_zone_from_system() const; + double get_unix_time_from_system() const; + uint64_t get_ticks_msec() const; + uint64_t get_ticks_usec() const; + + Time(); + virtual ~Time(); +}; + +#endif // TIME_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index f1b1b98bea..f67d615418 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -68,6 +68,7 @@ #include "core/object/class_db.h" #include "core/object/undo_redo.h" #include "core/os/main_loop.h" +#include "core/os/time.h" #include "core/string/optimized_translation.h" #include "core/string/translation.h" @@ -131,7 +132,7 @@ void register_core_types() { ClassDB::register_virtual_class<Script>(); - ClassDB::register_class<Reference>(); + ClassDB::register_class<RefCounted>(); ClassDB::register_class<WeakRef>(); ClassDB::register_class<Resource>(); ClassDB::register_class<Image>(); @@ -258,6 +259,7 @@ void register_core_singletons() { ClassDB::register_class<_JSON>(); ClassDB::register_class<Expression>(); ClassDB::register_class<_EngineDebugger>(); + ClassDB::register_class<Time>(); Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton())); @@ -274,6 +276,7 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton())); } void unregister_core_types() { diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index ad768f7140..d6b84cabc9 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -30,7 +30,7 @@ #include "translation_po.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #ifdef DEBUG_TRANSLATION_PO void TranslationPO::print_translation_map() { diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index bdb66526a4..83ede0b11b 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -54,7 +54,7 @@ #define snprintf _snprintf_s #endif -#define MAX_DIGITS 6 +#define MAX_DECIMALS 32 #define UPPERCASE(m_c) (((m_c) >= 'a' && (m_c) <= 'z') ? ((m_c) - ('a' - 'A')) : (m_c)) #define LOWERCASE(m_c) (((m_c) >= 'A' && (m_c) <= 'Z') ? ((m_c) + ('a' - 'A')) : (m_c)) #define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9') @@ -939,7 +939,7 @@ const char32_t *String::get_data() const { } void String::erase(int p_pos, int p_chars) { - *this = left(p_pos) + substr(p_pos + p_chars, length() - ((p_pos + p_chars))); + *this = left(MAX(p_pos, 0)) + substr(p_pos + p_chars, length() - ((p_pos + p_chars))); } String String::capitalize() const { @@ -1379,8 +1379,11 @@ String String::num(double p_num, int p_decimals) { } #ifndef NO_USE_STDLIB - if (p_decimals > 16) { - p_decimals = 16; + if (p_decimals < 0) { + p_decimals = 14 - (int)floor(log10(p_num)); + } + if (p_decimals > MAX_DECIMALS) { + p_decimals = MAX_DECIMALS; } char fmt[7]; @@ -1391,7 +1394,6 @@ String String::num(double p_num, int p_decimals) { fmt[1] = 'l'; fmt[2] = 'f'; fmt[3] = 0; - } else if (p_decimals < 10) { fmt[2] = '0' + p_decimals; fmt[3] = 'l'; @@ -1458,8 +1460,9 @@ String String::num(double p_num, int p_decimals) { double dec = p_num - (double)((int)p_num); int digit = 0; - if (p_decimals > MAX_DIGITS) - p_decimals = MAX_DIGITS; + if (p_decimals > MAX_DECIMALS) { + p_decimals = MAX_DECIMALS; + } int dec_int = 0; int dec_max = 0; @@ -1471,16 +1474,18 @@ String String::num(double p_num, int p_decimals) { digit++; if (p_decimals == -1) { - if (digit == MAX_DIGITS) //no point in going to infinite + if (digit == MAX_DECIMALS) { //no point in going to infinite break; + } if (dec - (double)((int)dec) < 1e-6) { break; } } - if (digit == p_decimals) + if (digit == p_decimals) { break; + } } dec *= 10; int last = (int)dec % 10; @@ -1589,7 +1594,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) { return s; } -String String::num_real(double p_num) { +String String::num_real(double p_num, bool p_trailing) { if (Math::is_nan(p_num)) { return "nan"; } @@ -1616,7 +1621,15 @@ String String::num_real(double p_num) { double dec = p_num - (double)((int)p_num); int digit = 0; - int decimals = MAX_DIGITS; + +#if REAL_T_IS_DOUBLE + int decimals = 14 - (int)floor(log10(p_num)); +#else + int decimals = 6 - (int)floor(log10(p_num)); +#endif + if (decimals > MAX_DECIMALS) { + decimals = MAX_DECIMALS; + } int dec_int = 0; int dec_max = 0; @@ -1656,8 +1669,10 @@ String String::num_real(double p_num) { dec_int /= 10; } sd = '.' + decimal; - } else { + } else if (p_trailing) { sd = ".0"; + } else { + sd = ""; } if (intn == 0) { @@ -3382,14 +3397,14 @@ String String::format(const Variant &values, String placeholder) const { if (value_arr.size() == 2) { Variant v_key = value_arr[0]; String key = v_key; - if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") { + if (key.left(1) == "\"" && key.right(1) == "\"") { key = key.substr(1, key.length() - 2); } Variant v_val = value_arr[1]; String val = v_val; - if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { + if (val.left(1) == "\"" && val.right(1) == "\"") { val = val.substr(1, val.length() - 2); } @@ -3401,7 +3416,7 @@ String String::format(const Variant &values, String placeholder) const { Variant v_val = values_arr[i]; String val = v_val; - if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { + if (val.left(1) == "\"" && val.right(1) == "\"") { val = val.substr(1, val.length() - 2); } @@ -3421,11 +3436,11 @@ String String::format(const Variant &values, String placeholder) const { String key = E->get(); String val = d[E->get()]; - if (key.left(1) == "\"" && key.right(key.length() - 1) == "\"") { + if (key.left(1) == "\"" && key.right(1) == "\"") { key = key.substr(1, key.length() - 2); } - if (val.left(1) == "\"" && val.right(val.length() - 1) == "\"") { + if (val.left(1) == "\"" && val.right(1) == "\"") { val = val.substr(1, val.length() - 2); } @@ -3529,6 +3544,10 @@ String String::repeat(int p_count) const { } String String::left(int p_pos) const { + if (p_pos < 0) { + p_pos = length() + p_pos; + } + if (p_pos <= 0) { return ""; } @@ -3541,15 +3560,19 @@ String String::left(int p_pos) const { } String String::right(int p_pos) const { - if (p_pos >= length()) { - return ""; + if (p_pos < 0) { + p_pos = length() + p_pos; } if (p_pos <= 0) { + return ""; + } + + if (p_pos >= length()) { return *this; } - return substr(p_pos, (length() - p_pos)); + return substr(length() - p_pos); } char32_t String::unicode_at(int p_idx) const { @@ -3778,7 +3801,7 @@ String String::humanize_size(uint64_t p_size) { return String::num(p_size / divisor).pad_decimals(digits) + " " + prefixes[prefix_idx]; } -bool String::is_abs_path() const { +bool String::is_absolute_path() const { if (length() > 1) { return (operator[](0) == '/' || operator[](0) == '\\' || find(":/") != -1 || find(":\\") != -1); } else if ((length()) == 1) { @@ -4388,7 +4411,7 @@ bool String::is_resource_file() const { } bool String::is_rel_path() const { - return !is_abs_path(); + return !is_absolute_path(); } String String::get_base_dir() const { diff --git a/core/string/ustring.h b/core/string/ustring.h index a56845deff..82cd3e1667 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -309,7 +309,7 @@ public: String unquote() const; static String num(double p_num, int p_decimals = -1); static String num_scientific(double p_num); - static String num_real(double p_num); + static String num_real(double p_num, bool p_trailing = true); static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false); static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false); static String chr(char32_t p_char); @@ -397,7 +397,7 @@ public: _FORCE_INLINE_ bool is_empty() const { return length() == 0; } // path functions - bool is_abs_path() const; + bool is_absolute_path() const; bool is_rel_path() const; bool is_resource_file() const; String path_to(const String &p_path) const; diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h new file mode 100644 index 0000000000..be9d0b5475 --- /dev/null +++ b/core/templates/bin_sorted_array.h @@ -0,0 +1,181 @@ +/*************************************************************************/ +/* bin_sorted_array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef BIN_SORTED_ARRAY_H +#define BIN_SORTED_ARRAY_H + +#include "core/templates/local_vector.h" +#include "core/templates/paged_array.h" + +template <class T> +class BinSortedArray { + PagedArray<T> array; + LocalVector<uint64_t> bin_limits; + + // Implement if elements need to keep track of their own index in the array. + _FORCE_INLINE_ virtual void _update_idx(T &r_element, uint64_t p_idx) {} + + _FORCE_INLINE_ void _swap(uint64_t p_a, uint64_t p_b) { + SWAP(array[p_a], array[p_b]); + _update_idx(array[p_a], p_a); + _update_idx(array[p_b], p_b); + } + +public: + uint64_t insert(T &p_element, uint64_t p_bin) { + array.push_back(p_element); + uint64_t new_idx = array.size() - 1; + _update_idx(p_element, new_idx); + bin_limits[0] = new_idx; + if (p_bin != 0) { + new_idx = move(new_idx, p_bin); + } + return new_idx; + } + + uint64_t move(uint64_t p_idx, uint64_t p_bin) { + ERR_FAIL_COND_V(p_idx >= array.size(), -1); + + uint64_t current_bin = bin_limits.size() - 1; + while (p_idx > bin_limits[current_bin]) { + current_bin--; + } + + if (p_bin == current_bin) { + return p_idx; + } + + uint64_t current_idx = p_idx; + if (p_bin > current_bin) { + while (p_bin > current_bin) { + uint64_t swap_idx = 0; + + if (current_bin == bin_limits.size() - 1) { + bin_limits.push_back(0); + } else { + bin_limits[current_bin + 1]++; + swap_idx = bin_limits[current_bin + 1]; + } + + if (current_idx != swap_idx) { + _swap(current_idx, swap_idx); + current_idx = swap_idx; + } + + current_bin++; + } + } else { + while (p_bin < current_bin) { + uint64_t swap_idx = bin_limits[current_bin]; + + if (current_idx != swap_idx) { + _swap(current_idx, swap_idx); + } + + if (current_bin == bin_limits.size() - 1 && bin_limits[current_bin] == 0) { + bin_limits.resize(bin_limits.size() - 1); + } else { + bin_limits[current_bin]--; + } + current_idx = swap_idx; + current_bin--; + } + } + + return current_idx; + } + + void remove(uint64_t p_idx) { + ERR_FAIL_COND(p_idx >= array.size()); + uint64_t new_idx = move(p_idx, 0); + uint64_t swap_idx = array.size() - 1; + + if (new_idx != swap_idx) { + _swap(new_idx, swap_idx); + } + + if (bin_limits[0] > 0) { + bin_limits[0]--; + } + + array.pop_back(); + } + + void set_page_pool(PagedArrayPool<T> *p_page_pool) { + array.set_page_pool(p_page_pool); + } + + _FORCE_INLINE_ const T &operator[](uint64_t p_index) const { + return array[p_index]; + } + + _FORCE_INLINE_ T &operator[](uint64_t p_index) { + return array[p_index]; + } + + int get_bin_count() { + if (array.size() == 0) { + return 0; + } + return bin_limits.size(); + } + + int get_bin_start(int p_bin) { + ERR_FAIL_COND_V(p_bin >= get_bin_count(), ~0U); + if ((unsigned int)p_bin == bin_limits.size() - 1) { + return 0; + } + return bin_limits[p_bin + 1] + 1; + } + + int get_bin_size(int p_bin) { + ERR_FAIL_COND_V(p_bin >= get_bin_count(), 0); + if ((unsigned int)p_bin == bin_limits.size() - 1) { + return bin_limits[p_bin] + 1; + } + return bin_limits[p_bin] - bin_limits[p_bin + 1]; + } + + void reset() { + array.reset(); + bin_limits.clear(); + bin_limits.push_back(0); + } + + BinSortedArray() { + bin_limits.push_back(0); + } + + virtual ~BinSortedArray() { + reset(); + } +}; + +#endif //BIN_SORTED_ARRAY_H diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp index 238bf3975c..04a8095f0b 100644 --- a/core/templates/command_queue_mt.cpp +++ b/core/templates/command_queue_mt.cpp @@ -70,35 +70,7 @@ CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() { return &sync_sems[idx]; } -bool CommandQueueMT::dealloc_one() { -tryagain: - if (dealloc_ptr == (write_ptr_and_epoch >> 1)) { - // The queue is empty - return false; - } - - uint32_t size = *(uint32_t *)&command_mem[dealloc_ptr]; - - if (size == 0) { - // End of command buffer wrap down - dealloc_ptr = 0; - goto tryagain; - } - - if (size & 1) { - // Still used, nothing can be deallocated - return false; - } - - dealloc_ptr += (size >> 1) + 8; - return true; -} - CommandQueueMT::CommandQueueMT(bool p_sync) { - command_mem_size = GLOBAL_DEF_RST("memory/limits/command_queue/multithreading_queue_size_kb", DEFAULT_COMMAND_MEM_SIZE_KB); - ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/command_queue/multithreading_queue_size_kb", PropertyInfo(Variant::INT, "memory/limits/command_queue/multithreading_queue_size_kb", PROPERTY_HINT_RANGE, "1,4096,1,or_greater")); - command_mem_size *= 1024; - command_mem = (uint8_t *)memalloc(command_mem_size); if (p_sync) { sync = memnew(Semaphore); } @@ -108,5 +80,4 @@ CommandQueueMT::~CommandQueueMT() { if (sync) { memdelete(sync); } - memfree(command_mem); } diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 0012cea72d..acc46da0d5 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -34,6 +34,8 @@ #include "core/os/memory.h" #include "core/os/mutex.h" #include "core/os/semaphore.h" +#include "core/string/print_string.h" +#include "core/templates/local_vector.h" #include "core/templates/simple_type.h" #include "core/typedefs.h" @@ -334,11 +336,7 @@ class CommandQueueMT { SYNC_SEMAPHORES = 8 }; - uint8_t *command_mem = nullptr; - uint32_t read_ptr_and_epoch = 0; - uint32_t write_ptr_and_epoch = 0; - uint32_t dealloc_ptr = 0; - uint32_t command_mem_size = 0; + LocalVector<uint8_t> command_mem; SyncSemaphore sync_sems[SYNC_SEMAPHORES]; Mutex mutex; Semaphore *sync = nullptr; @@ -346,138 +344,47 @@ class CommandQueueMT { template <class T> T *allocate() { // alloc size is size+T+safeguard - uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)) + 8; - - // Assert that the buffer is big enough to hold at least two messages. - ERR_FAIL_COND_V(alloc_size * 2 + sizeof(uint32_t) > command_mem_size, nullptr); - - tryagain: - uint32_t write_ptr = write_ptr_and_epoch >> 1; - - if (write_ptr < dealloc_ptr) { - // behind dealloc_ptr, check that there is room - if ((dealloc_ptr - write_ptr) <= alloc_size) { - // There is no more room, try to deallocate something - if (dealloc_one()) { - goto tryagain; - } - return nullptr; - } - } else { - // ahead of dealloc_ptr, check that there is room - - if ((command_mem_size - write_ptr) < alloc_size + sizeof(uint32_t)) { - // no room at the end, wrap down; - - if (dealloc_ptr == 0) { // don't want write_ptr to become dealloc_ptr - - // There is no more room, try to deallocate something - if (dealloc_one()) { - goto tryagain; - } - return nullptr; - } - - // if this happens, it's a bug - ERR_FAIL_COND_V((command_mem_size - write_ptr) < 8, nullptr); - // zero means, wrap to beginning - - uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = 1; - write_ptr_and_epoch = 0 | (1 & ~write_ptr_and_epoch); // Invert epoch. - // See if we can get the thread to run and clear up some more space while we wait. - // This is required if alloc_size * 2 + 4 > COMMAND_MEM_SIZE - if (sync) { - sync->post(); - } - goto tryagain; - } - } - // Allocate the size and the 'in use' bit. - // First bit used to mark if command is still in use (1) - // or if it has been destroyed and can be deallocated (0). - uint32_t size = (sizeof(T) + 8 - 1) & ~(8 - 1); - uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = (size << 1) | 1; - write_ptr += 8; - // allocate the command - T *cmd = memnew_placement(&command_mem[write_ptr], T); - write_ptr += size; - write_ptr_and_epoch = (write_ptr << 1) | (write_ptr_and_epoch & 1); + uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)); + uint64_t size = command_mem.size(); + command_mem.resize(size + alloc_size + 8); + *(uint64_t *)&command_mem[size] = alloc_size; + T *cmd = memnew_placement(&command_mem[size + 8], T); return cmd; } template <class T> T *allocate_and_lock() { lock(); - T *ret; - - while ((ret = allocate<T>()) == nullptr) { - unlock(); - // sleep a little until fetch happened and some room is made - wait_for_flush(); - lock(); - } - + T *ret = allocate<T>(); return ret; } - bool flush_one(bool p_lock = true) { - if (p_lock) { - lock(); - } - tryagain: - - // tried to read an empty queue - if (read_ptr_and_epoch == write_ptr_and_epoch) { - if (p_lock) { - unlock(); - } - return false; - } - - uint32_t read_ptr = read_ptr_and_epoch >> 1; - uint32_t size_ptr = read_ptr; - uint32_t size = *(uint32_t *)&command_mem[read_ptr] >> 1; - - if (size == 0) { - *(uint32_t *)&command_mem[read_ptr] = 0; // clear in-use bit. - //end of ringbuffer, wrap - read_ptr_and_epoch = 0 | (1 & ~read_ptr_and_epoch); // Invert epoch. - goto tryagain; - } - - read_ptr += 8; + void _flush() { + lock(); - CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); + uint64_t read_ptr = 0; + uint64_t limit = command_mem.size(); - read_ptr += size; + while (read_ptr < limit) { + uint64_t size = *(uint64_t *)&command_mem[read_ptr]; + read_ptr += 8; + CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); - read_ptr_and_epoch = (read_ptr << 1) | (read_ptr_and_epoch & 1); + cmd->call(); //execute the function + cmd->post(); //release in case it needs sync/ret + cmd->~CommandBase(); //should be done, so erase the command - if (p_lock) { - unlock(); - } - cmd->call(); - if (p_lock) { - lock(); + read_ptr += size; } - cmd->post(); - cmd->~CommandBase(); - *(uint32_t *)&command_mem[size_ptr] &= ~1; - - if (p_lock) { - unlock(); - } - return true; + command_mem.clear(); + unlock(); } void lock(); void unlock(); void wait_for_flush(); SyncSemaphore *_alloc_sync_sem(); - bool dealloc_one(); public: /* NORMAL PUSH COMMANDS */ @@ -492,23 +399,19 @@ public: DECL_PUSH_AND_SYNC(0) SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 15) - void wait_and_flush_one() { - ERR_FAIL_COND(!sync); - sync->wait(); - flush_one(); - } - _FORCE_INLINE_ void flush_if_pending() { - if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) { - flush_all(); + if (unlikely(command_mem.size() > 0)) { + _flush(); } } void flush_all() { - //ERR_FAIL_COND(sync); - lock(); - while (flush_one(false)) { - } - unlock(); + _flush(); + } + + void wait_and_flush() { + ERR_FAIL_COND(!sync); + sync->wait(); + _flush(); } CommandQueueMT(bool p_sync); diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index dc378aed69..1257b54449 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -291,7 +291,7 @@ public: } /** - * Same as get, except it can return nullptr when item was not found. + * Same as get, except it can return nullptr when item was not found. * This is mainly used for speed purposes. */ @@ -324,7 +324,7 @@ public: } /** - * Same as get, except it can return nullptr when item was not found. + * Same as get, except it can return nullptr when item was not found. * This version is custom, will take a hash and a custom key (that should support operator==() */ @@ -443,7 +443,7 @@ public: /** * Get the next key to p_key, and the first key if p_key is null. - * Returns a pointer to the next key if found, nullptr otherwise. + * Returns a pointer to the next key if found, nullptr otherwise. * Adding/Removing elements while iterating will, of course, have unexpected results, don't do it. * * Example: diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h index 2c7c64cd78..025cc30db4 100644 --- a/core/templates/oa_hash_map.h +++ b/core/templates/oa_hash_map.h @@ -231,7 +231,7 @@ public: /** * returns true if the value was found, false otherwise. * - * if r_data is not nullptr then the value will be written to the object + * if r_data is not nullptr then the value will be written to the object * it points to. */ bool lookup(const TKey &p_key, TValue &r_data) const { @@ -249,7 +249,7 @@ public: /** * returns true if the value was found, false otherwise. * - * if r_data is not nullptr then the value will be written to the object + * if r_data is not nullptr then the value will be written to the object * it points to. */ TValue *lookup_ptr(const TKey &p_key) const { diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h index 7002034710..481289309f 100644 --- a/core/templates/paged_allocator.h +++ b/core/templates/paged_allocator.h @@ -35,6 +35,8 @@ #include "core/os/spin_lock.h" #include "core/typedefs.h" +#include <type_traits> + template <class T, bool thread_safe = false> class PagedAllocator { T **page_pool = nullptr; @@ -89,8 +91,10 @@ public: allocs_available++; } - void reset() { - ERR_FAIL_COND(allocs_available < pages_allocated * page_size); + void reset(bool p_allow_unfreed = false) { + if (!p_allow_unfreed || !std::is_trivially_destructible<T>::value) { + ERR_FAIL_COND(allocs_available < pages_allocated * page_size); + } if (pages_allocated) { for (uint32_t i = 0; i < pages_allocated; i++) { memfree(page_pool[i]); diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 3c7e2a0719..09cf785390 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -366,8 +366,8 @@ Array Array::filter(const Callable &p_callable) const { new_arr.resize(size()); int accepted_count = 0; + const Variant *argptrs[1]; for (int i = 0; i < size(); i++) { - const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *)); argptrs[0] = &get(i); Variant result; @@ -392,8 +392,8 @@ Array Array::map(const Callable &p_callable) const { Array new_arr; new_arr.resize(size()); + const Variant *argptrs[1]; for (int i = 0; i < size(); i++) { - const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *)); argptrs[0] = &get(i); Variant result; @@ -417,8 +417,8 @@ Variant Array::reduce(const Callable &p_callable, const Variant &p_accum) const start = 1; } + const Variant *argptrs[2]; for (int i = start; i < size(); i++) { - const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * 2); argptrs[0] = &ret; argptrs[1] = &get(i); diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index e06b3e07ef..34b3e3ea35 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -33,7 +33,7 @@ #include "callable_bind.h" #include "core/object/message_queue.h" #include "core/object/object.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const { @@ -50,6 +50,15 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu custom->call(p_arguments, p_argcount, r_return_value, r_call_error); } else { Object *obj = ObjectDB::get_instance(ObjectID(object)); +#ifdef DEBUG_ENABLED + if (!obj) { + r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; + r_call_error.argument = 0; + r_call_error.expected = 0; + r_return_value = Variant(); + return; + } +#endif r_return_value = obj->call(method, p_arguments, p_argcount, r_call_error); } } diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index e91029f330..d4ec5e570c 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -122,10 +122,10 @@ MAKE_PTRARG_BY_REFERENCE(Vector3); MAKE_PTRARG_BY_REFERENCE(Vector3i); MAKE_PTRARG(Transform2D); MAKE_PTRARG_BY_REFERENCE(Plane); -MAKE_PTRARG(Quat); +MAKE_PTRARG(Quaternion); MAKE_PTRARG_BY_REFERENCE(AABB); MAKE_PTRARG_BY_REFERENCE(Basis); -MAKE_PTRARG_BY_REFERENCE(Transform); +MAKE_PTRARG_BY_REFERENCE(Transform3D); MAKE_PTRARG_BY_REFERENCE(Color); MAKE_PTRARG(StringName); MAKE_PTRARG(NodePath); diff --git a/core/variant/type_info.h b/core/variant/type_info.h index d5b6d85dfb..76cb065d10 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -146,10 +146,10 @@ MAKE_TYPE_INFO(Rect2i, Variant::RECT2I) MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPE_INFO(Plane, Variant::PLANE) -MAKE_TYPE_INFO(Quat, Variant::QUAT) +MAKE_TYPE_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPE_INFO(AABB, Variant::AABB) MAKE_TYPE_INFO(Basis, Variant::BASIS) -MAKE_TYPE_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPE_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPE_INFO(Color, Variant::COLOR) MAKE_TYPE_INFO(StringName, Variant::STRING_NAME) MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH) diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h index e0309aa3fe..900dcf7689 100644 --- a/core/variant/typed_array.h +++ b/core/variant/typed_array.h @@ -98,10 +98,10 @@ MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY(Plane, Variant::PLANE) -MAKE_TYPED_ARRAY(Quat, Variant::QUAT) +MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY(AABB, Variant::AABB) MAKE_TYPED_ARRAY(Basis, Variant::BASIS) -MAKE_TYPED_ARRAY(Transform, Variant::TRANSFORM) +MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY(Color, Variant::COLOR) MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH) @@ -196,10 +196,10 @@ MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE) -MAKE_TYPED_ARRAY_INFO(Quat, Variant::QUAT) +MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB) MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS) -MAKE_TYPED_ARRAY_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR) MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH) diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 333dd8e8d1..4e45862fd3 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -91,16 +91,16 @@ String Variant::get_type_name(Variant::Type p_type) { case AABB: { return "AABB"; } break; - case QUAT: { - return "Quat"; + case QUATERNION: { + return "Quaternion"; } break; case BASIS: { return "Basis"; } break; - case TRANSFORM: { - return "Transform"; + case TRANSFORM3D: { + return "Transform3D"; } break; @@ -275,7 +275,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case TRANSFORM2D: { static const Type valid[] = { - TRANSFORM, + TRANSFORM3D, NIL }; @@ -300,7 +300,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; - case QUAT: { + case QUATERNION: { static const Type valid[] = { BASIS, NIL @@ -311,7 +311,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case BASIS: { static const Type valid[] = { - QUAT, + QUATERNION, VECTOR3, NIL }; @@ -319,10 +319,10 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { valid_types = valid; } break; - case TRANSFORM: { + case TRANSFORM3D: { static const Type valid[] = { TRANSFORM2D, - QUAT, + QUATERNION, BASIS, NIL }; @@ -582,7 +582,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case TRANSFORM2D: { static const Type valid[] = { - TRANSFORM, + TRANSFORM3D, NIL }; @@ -607,7 +607,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; - case QUAT: { + case QUATERNION: { static const Type valid[] = { BASIS, NIL @@ -618,7 +618,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case BASIS: { static const Type valid[] = { - QUAT, + QUATERNION, VECTOR3, NIL }; @@ -626,10 +626,10 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; - case TRANSFORM: { + case TRANSFORM3D: { static const Type valid[] = { TRANSFORM2D, - QUAT, + QUATERNION, BASIS, NIL }; @@ -873,16 +873,16 @@ bool Variant::is_zero() const { case AABB: { return *_data._aabb == ::AABB(); } break; - case QUAT: { - return *reinterpret_cast<const Quat *>(_data._mem) == Quat(); + case QUATERNION: { + return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion(); } break; case BASIS: { return *_data._basis == Basis(); } break; - case TRANSFORM: { - return *_data._transform == Transform(); + case TRANSFORM3D: { + return *_data._transform3d == Transform3D(); } break; @@ -1092,16 +1092,16 @@ void Variant::reference(const Variant &p_variant) { case AABB: { _data._aabb = memnew(::AABB(*p_variant._data._aabb)); } break; - case QUAT: { - memnew_placement(_data._mem, Quat(*reinterpret_cast<const Quat *>(p_variant._data._mem))); + case QUATERNION: { + memnew_placement(_data._mem, Quaternion(*reinterpret_cast<const Quaternion *>(p_variant._data._mem))); } break; case BASIS: { _data._basis = memnew(Basis(*p_variant._data._basis)); } break; - case TRANSFORM: { - _data._transform = memnew(Transform(*p_variant._data._transform)); + case TRANSFORM3D: { + _data._transform3d = memnew(Transform3D(*p_variant._data._transform3d)); } break; // misc types @@ -1115,9 +1115,9 @@ void Variant::reference(const Variant &p_variant) { case OBJECT: { memnew_placement(_data._mem, ObjData); - if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); - if (!reference->reference()) { + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) { + RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj); + if (!ref_counted->reference()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); break; @@ -1254,8 +1254,8 @@ void Variant::zero() { case PLANE: *reinterpret_cast<Plane *>(this->_data._mem) = Plane(); break; - case QUAT: - *reinterpret_cast<Quat *>(this->_data._mem) = Quat(); + case QUATERNION: + *reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion(); break; case COLOR: *reinterpret_cast<Color *>(this->_data._mem) = Color(); @@ -1275,7 +1275,7 @@ void Variant::_clear_internal() { // no point, they don't allocate memory VECTOR3, PLANE, - QUAT, + QUATERNION, COLOR, VECTOR2, RECT2 @@ -1289,8 +1289,8 @@ void Variant::_clear_internal() { case BASIS: { memdelete(_data._basis); } break; - case TRANSFORM: { - memdelete(_data._transform); + case TRANSFORM3D: { + memdelete(_data._transform3d); } break; // misc types @@ -1301,11 +1301,11 @@ void Variant::_clear_internal() { reinterpret_cast<NodePath *>(_data._mem)->~NodePath(); } break; case OBJECT: { - if (_get_obj().id.is_reference()) { + if (_get_obj().id.is_ref_counted()) { //we are safe that there is a reference here - Reference *reference = static_cast<Reference *>(_get_obj().obj); - if (reference->unreference()) { - memdelete(reference); + RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj); + if (ref_counted->unreference()) { + memdelete(ref_counted); } } _get_obj().obj = nullptr; @@ -1636,60 +1636,35 @@ String Variant::stringify(List<const void *> &stack) const { case STRING: return *reinterpret_cast<const String *>(_data._mem); case VECTOR2: - return "(" + operator Vector2() + ")"; + return operator Vector2(); case VECTOR2I: - return "(" + operator Vector2i() + ")"; + return operator Vector2i(); case RECT2: - return "(" + operator Rect2() + ")"; + return operator Rect2(); case RECT2I: - return "(" + operator Rect2i() + ")"; - case TRANSFORM2D: { - Transform2D mat32 = operator Transform2D(); - return "(" + Variant(mat32.elements[0]).operator String() + ", " + Variant(mat32.elements[1]).operator String() + ", " + Variant(mat32.elements[2]).operator String() + ")"; - } break; + return operator Rect2i(); + case TRANSFORM2D: + return operator Transform2D(); case VECTOR3: - return "(" + operator Vector3() + ")"; + return operator Vector3(); case VECTOR3I: - return "(" + operator Vector3i() + ")"; + return operator Vector3i(); case PLANE: return operator Plane(); - //case QUAT: case AABB: return operator ::AABB(); - case QUAT: - return "(" + operator Quat() + ")"; - case BASIS: { - Basis mat3 = operator Basis(); - - String mtx("("); - for (int i = 0; i < 3; i++) { - if (i != 0) { - mtx += ", "; - } - - mtx += "("; - - for (int j = 0; j < 3; j++) { - if (j != 0) { - mtx += ", "; - } - - mtx += Variant(mat3.elements[i][j]).operator String(); - } - - mtx += ")"; - } - - return mtx + ")"; - } break; - case TRANSFORM: - return operator Transform(); + case QUATERNION: + return operator Quaternion(); + case BASIS: + return operator Basis(); + case TRANSFORM3D: + return operator Transform3D(); case STRING_NAME: return operator StringName(); case NODE_PATH: return operator NodePath(); case COLOR: - return String::num(operator Color().r) + "," + String::num(operator Color().g) + "," + String::num(operator Color().b) + "," + String::num(operator Color().a); + return operator Color(); case DICTIONARY: { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); if (stack.find(d.id())) { @@ -1723,6 +1698,7 @@ String Variant::stringify(List<const void *> &stack) const { } str += "}"; + stack.erase(d.id()); return str; } break; case PACKED_VECTOR2_ARRAY: { @@ -1826,12 +1802,13 @@ String Variant::stringify(List<const void *> &stack) const { } str += "]"; + stack.erase(arr.id()); return str; } break; case OBJECT: { if (_get_obj().obj) { - if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { return "[Freed Object]"; } @@ -1956,39 +1933,39 @@ Variant::operator ::AABB() const { Variant::operator Basis() const { if (type == BASIS) { return *_data._basis; - } else if (type == QUAT) { - return *reinterpret_cast<const Quat *>(_data._mem); + } else if (type == QUATERNION) { + return *reinterpret_cast<const Quaternion *>(_data._mem); } else if (type == VECTOR3) { return Basis(*reinterpret_cast<const Vector3 *>(_data._mem)); - } else if (type == TRANSFORM) { // unexposed in Variant::can_convert? - return _data._transform->basis; + } else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert? + return _data._transform3d->basis; } else { return Basis(); } } -Variant::operator Quat() const { - if (type == QUAT) { - return *reinterpret_cast<const Quat *>(_data._mem); +Variant::operator Quaternion() const { + if (type == QUATERNION) { + return *reinterpret_cast<const Quaternion *>(_data._mem); } else if (type == BASIS) { return *_data._basis; - } else if (type == TRANSFORM) { - return _data._transform->basis; + } else if (type == TRANSFORM3D) { + return _data._transform3d->basis; } else { - return Quat(); + return Quaternion(); } } -Variant::operator Transform() const { - if (type == TRANSFORM) { - return *_data._transform; +Variant::operator Transform3D() const { + if (type == TRANSFORM3D) { + return *_data._transform3d; } else if (type == BASIS) { - return Transform(*_data._basis, Vector3()); - } else if (type == QUAT) { - return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3()); + return Transform3D(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform3D(Basis(*reinterpret_cast<const Quaternion *>(_data._mem)), Vector3()); } else if (type == TRANSFORM2D) { const Transform2D &t = *_data._transform2d; - Transform m; + Transform3D m; m.basis.elements[0][0] = t.elements[0][0]; m.basis.elements[1][0] = t.elements[0][1]; m.basis.elements[0][1] = t.elements[1][0]; @@ -1997,15 +1974,15 @@ Variant::operator Transform() const { m.origin[1] = t.elements[2][1]; return m; } else { - return Transform(); + return Transform3D(); } } Variant::operator Transform2D() const { if (type == TRANSFORM2D) { return *_data._transform2d; - } else if (type == TRANSFORM) { - const Transform &t = *_data._transform; + } else if (type == TRANSFORM3D) { + const Transform3D &t = *_data._transform3d; Transform2D m; m.elements[0][0] = t.basis.elements[0][0]; m.elements[0][1] = t.basis.elements[1][0]; @@ -2495,14 +2472,14 @@ Variant::Variant(const Basis &p_matrix) { _data._basis = memnew(Basis(p_matrix)); } -Variant::Variant(const Quat &p_quat) { - type = QUAT; - memnew_placement(_data._mem, Quat(p_quat)); +Variant::Variant(const Quaternion &p_quaternion) { + type = QUATERNION; + memnew_placement(_data._mem, Quaternion(p_quaternion)); } -Variant::Variant(const Transform &p_transform) { - type = TRANSFORM; - _data._transform = memnew(Transform(p_transform)); +Variant::Variant(const Transform3D &p_transform) { + type = TRANSFORM3D; + _data._transform3d = memnew(Transform3D(p_transform)); } Variant::Variant(const Transform2D &p_transform) { @@ -2531,9 +2508,9 @@ Variant::Variant(const Object *p_object) { memnew_placement(_data._mem, ObjData); if (p_object) { - if (p_object->is_reference()) { - Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(p_object)); - if (!reference->init_ref()) { + if (p_object->is_ref_counted()) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_object)); + if (!ref_counted->init_ref()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); return; @@ -2739,14 +2716,14 @@ void Variant::operator=(const Variant &p_variant) { case AABB: { *_data._aabb = *(p_variant._data._aabb); } break; - case QUAT: { - *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem); + case QUATERNION: { + *reinterpret_cast<Quaternion *>(_data._mem) = *reinterpret_cast<const Quaternion *>(p_variant._data._mem); } break; case BASIS: { *_data._basis = *(p_variant._data._basis); } break; - case TRANSFORM: { - *_data._transform = *(p_variant._data._transform); + case TRANSFORM3D: { + *_data._transform3d = *(p_variant._data._transform3d); } break; // misc types @@ -2757,17 +2734,17 @@ void Variant::operator=(const Variant &p_variant) { *reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast<const ::RID *>(p_variant._data._mem); } break; case OBJECT: { - if (_get_obj().id.is_reference()) { + if (_get_obj().id.is_ref_counted()) { //we are safe that there is a reference here - Reference *reference = static_cast<Reference *>(_get_obj().obj); - if (reference->unreference()) { - memdelete(reference); + RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj); + if (ref_counted->unreference()) { + memdelete(ref_counted); } } - if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); - if (!reference->reference()) { + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) { + RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj); + if (!ref_counted->reference()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); break; @@ -2916,11 +2893,11 @@ uint32_t Variant::hash() const { return hash; } break; - case QUAT: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->x); - hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->y, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->z, hash); - return hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->w, hash); + case QUATERNION: { + uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->x); + hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->y, hash); + hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->z, hash); + return hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->w, hash); } break; case BASIS: { @@ -2934,13 +2911,13 @@ uint32_t Variant::hash() const { return hash; } break; - case TRANSFORM: { + case TRANSFORM3D: { uint32_t hash = 5831; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - hash = hash_djb2_one_float(_data._transform->basis.elements[i][j], hash); + hash = hash_djb2_one_float(_data._transform3d->basis.elements[i][j], hash); } - hash = hash_djb2_one_float(_data._transform->origin[i], hash); + hash = hash_djb2_one_float(_data._transform3d->origin[i], hash); } return hash; @@ -3127,7 +3104,7 @@ uint32_t Variant::hash() const { (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) -#define hash_compare_quat(p_lhs, p_rhs) \ +#define hash_compare_quaternion(p_lhs, p_rhs) \ (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \ @@ -3235,11 +3212,11 @@ bool Variant::hash_compare(const Variant &p_variant) const { } break; - case QUAT: { - const Quat *l = reinterpret_cast<const Quat *>(_data._mem); - const Quat *r = reinterpret_cast<const Quat *>(p_variant._data._mem); + case QUATERNION: { + const Quaternion *l = reinterpret_cast<const Quaternion *>(_data._mem); + const Quaternion *r = reinterpret_cast<const Quaternion *>(p_variant._data._mem); - return hash_compare_quat(*l, *r); + return hash_compare_quaternion(*l, *r); } break; case BASIS: { @@ -3255,9 +3232,9 @@ bool Variant::hash_compare(const Variant &p_variant) const { return true; } break; - case TRANSFORM: { - const Transform *l = _data._transform; - const Transform *r = p_variant._data._transform; + case TRANSFORM3D: { + const Transform3D *l = _data._transform3d; + const Transform3D *r = p_variant._data._transform3d; for (int i = 0; i < 3; i++) { if (!(hash_compare_vector3(l->basis.elements[i], r->basis.elements[i]))) { @@ -3324,7 +3301,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { } bool Variant::is_ref() const { - return type == OBJECT && _get_obj().id.is_reference(); + return type == OBJECT && _get_obj().id.is_ref_counted(); } Vector<Variant> varray() { diff --git a/core/variant/variant.h b/core/variant/variant.h index 7f3c3477fc..75316da63f 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -37,9 +37,9 @@ #include "core/math/color.h" #include "core/math/face3.h" #include "core/math/plane.h" -#include "core/math/quat.h" -#include "core/math/transform.h" +#include "core/math/quaternion.h" #include "core/math/transform_2d.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/math/vector3i.h" #include "core/object/object_id.h" @@ -88,10 +88,10 @@ public: VECTOR3I, TRANSFORM2D, PLANE, - QUAT, + QUATERNION, AABB, BASIS, - TRANSFORM, + TRANSFORM3D, // misc types COLOR, @@ -200,7 +200,7 @@ private: Transform2D *_transform2d; ::AABB *_aabb; Basis *_basis; - Transform *_transform; + Transform3D *_transform3d; PackedArrayRefBase *packed_array; void *_ptr; //generic pointer uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]; @@ -225,7 +225,7 @@ private: false, //VECTOR3I, true, //TRANSFORM2D, false, //PLANE, - false, //QUAT, + false, //QUATERNION, true, //AABB, true, //BASIS, true, //TRANSFORM, @@ -320,10 +320,10 @@ public: operator Vector3i() const; operator Plane() const; operator ::AABB() const; - operator Quat() const; + operator Quaternion() const; operator Basis() const; - operator Transform() const; operator Transform2D() const; + operator Transform3D() const; operator Color() const; operator NodePath() const; @@ -392,10 +392,10 @@ public: Variant(const Vector3i &p_vector3i); Variant(const Plane &p_plane); Variant(const ::AABB &p_aabb); - Variant(const Quat &p_quat); + Variant(const Quaternion &p_quat); Variant(const Basis &p_matrix); Variant(const Transform2D &p_transform); - Variant(const Transform &p_transform); + Variant(const Transform3D &p_transform); Variant(const Color &p_color); Variant(const NodePath &p_node_path); Variant(const ::RID &p_rid); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index efaaa8cd19..05ed35c760 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -611,6 +611,9 @@ struct _VariantCall { if (buffer_size <= 0) { ERR_FAIL_V_MSG(decompressed, "Decompression buffer size must be greater than zero."); } + if (p_instance->size() == 0) { + ERR_FAIL_V_MSG(decompressed, "Compressed buffer size must be greater than zero."); + } decompressed.resize(buffer_size); int result = Compression::decompress(decompressed.ptrw(), buffer_size, p_instance->ptr(), p_instance->size(), mode); @@ -969,7 +972,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg return; } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return; } @@ -1362,7 +1365,7 @@ static void _register_variant_builtin_methods() { // FIXME: Static function, not sure how to bind //bind_method(String, humanize_size, sarray("size"), varray()); - bind_method(String, is_abs_path, sarray(), varray()); + bind_method(String, is_absolute_path, sarray(), varray()); bind_method(String, is_rel_path, sarray(), varray()); bind_method(String, get_base_dir, sarray(), varray()); bind_method(String, get_file, sarray(), varray()); @@ -1416,6 +1419,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, distance_squared_to, sarray("to"), varray()); bind_method(Vector2, length, sarray(), varray()); bind_method(Vector2, length_squared, sarray(), varray()); + bind_method(Vector2, limit_length, sarray("length"), varray(1.0)); bind_method(Vector2, normalized, sarray(), varray()); bind_method(Vector2, is_normalized, sarray(), varray()); bind_method(Vector2, is_equal_approx, sarray("to"), varray()); @@ -1439,14 +1443,15 @@ static void _register_variant_builtin_methods() { bind_method(Vector2, cross, sarray("with"), varray()); bind_method(Vector2, abs, sarray(), varray()); bind_method(Vector2, sign, sarray(), varray()); + bind_method(Vector2, clamp, sarray("min", "max"), varray()); bind_method(Vector2, snapped, sarray("step"), varray()); - bind_method(Vector2, clamped, sarray("length"), varray()); /* Vector2i */ bind_method(Vector2i, aspect, sarray(), varray()); bind_method(Vector2i, sign, sarray(), varray()); bind_method(Vector2i, abs, sarray(), varray()); + bind_method(Vector2i, clamp, sarray("min", "max"), varray()); /* Rect2 */ @@ -1490,10 +1495,12 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, distance_squared_to, sarray("b"), varray()); bind_method(Vector3, length, sarray(), varray()); bind_method(Vector3, length_squared, sarray(), varray()); + bind_method(Vector3, limit_length, sarray("length"), varray(1.0)); bind_method(Vector3, normalized, sarray(), varray()); bind_method(Vector3, is_normalized, sarray(), varray()); bind_method(Vector3, is_equal_approx, sarray("to"), varray()); bind_method(Vector3, inverse, sarray(), varray()); + bind_method(Vector3, clamp, sarray("min", "max"), varray()); bind_method(Vector3, snapped, sarray("step"), varray()); bind_method(Vector3, rotated, sarray("by_axis", "phi"), varray()); bind_method(Vector3, lerp, sarray("to", "weight"), varray()); @@ -1522,6 +1529,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector3i, max_axis, sarray(), varray()); bind_method(Vector3i, sign, sarray(), varray()); bind_method(Vector3i, abs, sarray(), varray()); + bind_method(Vector3i, clamp, sarray("min", "max"), varray()); /* Plane */ @@ -1536,19 +1544,19 @@ static void _register_variant_builtin_methods() { bind_methodv(Plane, intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray()); bind_methodv(Plane, intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray()); - /* Quat */ + /* Quaternion */ - bind_method(Quat, length, sarray(), varray()); - bind_method(Quat, length_squared, sarray(), varray()); - bind_method(Quat, normalized, sarray(), varray()); - bind_method(Quat, is_normalized, sarray(), varray()); - bind_method(Quat, is_equal_approx, sarray("to"), varray()); - bind_method(Quat, inverse, sarray(), varray()); - bind_method(Quat, dot, sarray("with"), varray()); - bind_method(Quat, slerp, sarray("to", "weight"), varray()); - bind_method(Quat, slerpni, sarray("to", "weight"), varray()); - bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); - bind_method(Quat, get_euler, sarray(), varray()); + bind_method(Quaternion, length, sarray(), varray()); + bind_method(Quaternion, length_squared, sarray(), varray()); + 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, inverse, sarray(), varray()); + bind_method(Quaternion, dot, sarray("with"), varray()); + bind_method(Quaternion, slerp, sarray("to", "weight"), varray()); + bind_method(Quaternion, slerpni, sarray("to", "weight"), varray()); + bind_method(Quaternion, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Quaternion, get_euler, sarray(), varray()); /* Color */ @@ -1559,6 +1567,7 @@ static void _register_variant_builtin_methods() { bind_method(Color, to_abgr64, sarray(), varray()); bind_method(Color, to_rgba64, sarray(), varray()); + bind_method(Color, clamp, sarray("min", "max"), varray(Color(0, 0, 0, 0), Color(1, 1, 1, 1))); bind_method(Color, inverted, sarray(), varray()); bind_method(Color, lerp, sarray("to", "weight"), varray()); bind_method(Color, lightened, sarray("amount"), varray()); @@ -1642,6 +1651,8 @@ 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, set_rotation, sarray("rotation"), varray()); + bind_method(Transform2D, looking_at, sarray("target"), varray(Transform2D())); /* Basis */ @@ -1659,7 +1670,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, get_orthogonal_index, sarray(), varray()); bind_method(Basis, slerp, sarray("to", "weight"), varray()); bind_method(Basis, is_equal_approx, sarray("b"), varray()); - bind_method(Basis, get_rotation_quat, sarray(), varray()); + bind_method(Basis, get_rotation_quaternion, sarray(), varray()); /* AABB */ @@ -1687,17 +1698,17 @@ static void _register_variant_builtin_methods() { bind_methodv(AABB, intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray()); bind_methodv(AABB, intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray()); - /* Transform */ + /* Transform3D */ - bind_method(Transform, inverse, sarray(), varray()); - bind_method(Transform, affine_inverse, sarray(), varray()); - bind_method(Transform, orthonormalized, sarray(), varray()); - bind_method(Transform, rotated, sarray("axis", "phi"), varray()); - bind_method(Transform, scaled, sarray("scale"), varray()); - bind_method(Transform, translated, sarray("offset"), varray()); - bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); - bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray()); - bind_method(Transform, is_equal_approx, sarray("xform"), varray()); + bind_method(Transform3D, inverse, sarray(), varray()); + bind_method(Transform3D, affine_inverse, sarray(), varray()); + bind_method(Transform3D, orthonormalized, sarray(), varray()); + bind_method(Transform3D, rotated, sarray("axis", "phi"), varray()); + bind_method(Transform3D, scaled, sarray("scale"), varray()); + bind_method(Transform3D, translated, sarray("offset"), varray()); + 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()); /* Dictionary */ @@ -2016,14 +2027,14 @@ static void _register_variant_builtin_methods() { _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)); - Transform identity_transform = Transform(); - Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); - Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0); - Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform); + Transform3D identity_transform = Transform3D(); + 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); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "IDENTITY", identity_transform); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_X", flip_x_transform); + _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 flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1); @@ -2038,7 +2049,7 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0)); _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0)); - _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1)); + _VariantCall::add_variant_constant(Variant::QUATERNION, "IDENTITY", Quaternion(0, 0, 0, 1)); } void Variant::_register_variant_methods() { diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index f0c9e52b46..9e3ab5897b 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -62,10 +62,10 @@ MAKE_PTRCONSTRUCT(Vector3); MAKE_PTRCONSTRUCT(Vector3i); MAKE_PTRCONSTRUCT(Transform2D); MAKE_PTRCONSTRUCT(Plane); -MAKE_PTRCONSTRUCT(Quat); +MAKE_PTRCONSTRUCT(Quaternion); MAKE_PTRCONSTRUCT(AABB); MAKE_PTRCONSTRUCT(Basis); -MAKE_PTRCONSTRUCT(Transform); +MAKE_PTRCONSTRUCT(Transform3D); MAKE_PTRCONSTRUCT(Color); MAKE_PTRCONSTRUCT(StringName); MAKE_PTRCONSTRUCT(NodePath); @@ -659,13 +659,13 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3")); add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d")); - add_constructor<VariantConstructNoArgs<Quat>>(sarray()); - add_constructor<VariantConstructor<Quat, Quat>>(sarray("from")); - add_constructor<VariantConstructor<Quat, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Quat, Vector3>>(sarray("euler")); - add_constructor<VariantConstructor<Quat, Vector3, double>>(sarray("axis", "angle")); - add_constructor<VariantConstructor<Quat, Vector3, Vector3>>(sarray("arc_from", "arc_to")); - add_constructor<VariantConstructor<Quat, double, double, double, double>>(sarray("x", "y", "z", "w")); + add_constructor<VariantConstructNoArgs<Quaternion>>(sarray()); + add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from")); + add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from")); + add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler")); + 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<VariantConstructNoArgs<::AABB>>(sarray()); add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from")); @@ -673,15 +673,15 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Basis>>(sarray()); add_constructor<VariantConstructor<Basis, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Basis, Quat>>(sarray("from")); + add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from")); add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi")); add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis")); - add_constructor<VariantConstructNoArgs<Transform>>(sarray()); - add_constructor<VariantConstructor<Transform, Transform>>(sarray("from")); - add_constructor<VariantConstructor<Transform, Basis, Vector3>>(sarray("basis", "origin")); - add_constructor<VariantConstructor<Transform, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin")); + add_constructor<VariantConstructNoArgs<Transform3D>>(sarray()); + add_constructor<VariantConstructor<Transform3D, Transform3D>>(sarray("from")); + add_constructor<VariantConstructor<Transform3D, Basis, Vector3>>(sarray("basis", "origin")); + add_constructor<VariantConstructor<Transform3D, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin")); add_constructor<VariantConstructNoArgs<Color>>(sarray()); add_constructor<VariantConstructor<Color, Color>>(sarray("from")); @@ -836,9 +836,9 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr void VariantInternal::object_assign(Variant *v, const Object *o) { if (o) { - if (o->is_reference()) { - Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(o)); - if (!reference->init_ref()) { + if (o->is_ref_counted()) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(o)); + if (!ref_counted->init_ref()) { v->_get_obj().obj = nullptr; v->_get_obj().id = ObjectID(); return; diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 7d33d85cd6..78e1ad06ae 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -43,17 +43,20 @@ public: v->type = p_type; switch (p_type) { - case Variant::AABB: - init_aabb(v); + case Variant::STRING: + init_string(v); break; case Variant::TRANSFORM2D: init_transform2d(v); break; - case Variant::TRANSFORM: - init_transform(v); + case Variant::AABB: + init_aabb(v); break; - case Variant::STRING: - init_string(v); + case Variant::BASIS: + init_basis(v); + break; + case Variant::TRANSFORM3D: + init_transform(v); break; case Variant::STRING_NAME: init_string_name(v); @@ -135,14 +138,14 @@ public: _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; } _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); } _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); } - _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); } - _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); } + _FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return reinterpret_cast<Quaternion *>(v->_data._mem); } + _FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return reinterpret_cast<const Quaternion *>(v->_data._mem); } _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; } _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; } _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; } _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; } - _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; } - _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; } + _FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return v->_data._transform3d; } + _FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return v->_data._transform3d; } // Misc types. _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); } @@ -192,6 +195,10 @@ public: v->type = GetTypeInfo<T>::VARIANT_TYPE; } + // Should be in the same order as Variant::Type for consistency. + // Those primitive and vector types don't need an `init_` method: + // Nil, bool, float, Vector2/i, Rect2/i, Vector3/i, Plane, Quat, Color, RID. + // Object is a special case, handled via `object_assign_null`. _FORCE_INLINE_ static void init_string(Variant *v) { memnew_placement(v->_data._mem, String); v->type = Variant::STRING; @@ -210,8 +217,8 @@ public: v->type = Variant::BASIS; } _FORCE_INLINE_ static void init_transform(Variant *v) { - v->_data._transform = memnew(Transform); - v->type = Variant::TRANSFORM; + v->_data._transform3d = memnew(Transform3D); + v->type = Variant::TRANSFORM3D; } _FORCE_INLINE_ static void init_string_name(Variant *v) { memnew_placement(v->_data._mem, StringName); @@ -278,7 +285,7 @@ public: v->clear(); } - static void object_assign(Variant *v, const Object *o); // Needs Reference, so it's implemented elsewhere. + static void object_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere. _FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) { object_assign(v, o->_get_obj().obj); @@ -313,12 +320,12 @@ public: return get_rect2(v); case Variant::RECT2I: return get_rect2i(v); - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: return get_transform(v); case Variant::TRANSFORM2D: return get_transform2d(v); - case Variant::QUAT: - return get_quat(v); + case Variant::QUATERNION: + return get_quaternion(v); case Variant::PLANE: return get_plane(v); case Variant::BASIS: @@ -391,12 +398,12 @@ public: return get_rect2(v); case Variant::RECT2I: return get_rect2i(v); - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: return get_transform(v); case Variant::TRANSFORM2D: return get_transform2d(v); - case Variant::QUAT: - return get_quat(v); + case Variant::QUATERNION: + return get_quaternion(v); case Variant::PLANE: return get_plane(v); case Variant::BASIS: @@ -583,9 +590,9 @@ struct VariantGetInternalPtr<Transform2D> { }; template <> -struct VariantGetInternalPtr<Transform> { - static Transform *get_ptr(Variant *v) { return VariantInternal::get_transform(v); } - static const Transform *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); } +struct VariantGetInternalPtr<Transform3D> { + static Transform3D *get_ptr(Variant *v) { return VariantInternal::get_transform(v); } + static const Transform3D *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); } }; template <> @@ -595,9 +602,9 @@ struct VariantGetInternalPtr<Plane> { }; template <> -struct VariantGetInternalPtr<Quat> { - static Quat *get_ptr(Variant *v) { return VariantInternal::get_quat(v); } - static const Quat *get_ptr(const Variant *v) { return VariantInternal::get_quat(v); } +struct VariantGetInternalPtr<Quaternion> { + static Quaternion *get_ptr(Variant *v) { return VariantInternal::get_quaternion(v); } + static const Quaternion *get_ptr(const Variant *v) { return VariantInternal::get_quaternion(v); } }; template <> @@ -812,9 +819,9 @@ struct VariantInternalAccessor<Transform2D> { }; template <> -struct VariantInternalAccessor<Transform> { - static _FORCE_INLINE_ const Transform &get(const Variant *v) { return *VariantInternal::get_transform(v); } - static _FORCE_INLINE_ void set(Variant *v, const Transform &p_value) { *VariantInternal::get_transform(v) = p_value; } +struct VariantInternalAccessor<Transform3D> { + static _FORCE_INLINE_ const Transform3D &get(const Variant *v) { return *VariantInternal::get_transform(v); } + static _FORCE_INLINE_ void set(Variant *v, const Transform3D &p_value) { *VariantInternal::get_transform(v) = p_value; } }; template <> @@ -824,9 +831,9 @@ struct VariantInternalAccessor<Plane> { }; template <> -struct VariantInternalAccessor<Quat> { - static _FORCE_INLINE_ const Quat &get(const Variant *v) { return *VariantInternal::get_quat(v); } - static _FORCE_INLINE_ void set(Variant *v, const Quat &p_value) { *VariantInternal::get_quat(v) = p_value; } +struct VariantInternalAccessor<Quaternion> { + static _FORCE_INLINE_ const Quaternion &get(const Variant *v) { return *VariantInternal::get_quaternion(v); } + static _FORCE_INLINE_ void set(Variant *v, const Quaternion &p_value) { *VariantInternal::get_quaternion(v) = p_value; } }; template <> @@ -1060,8 +1067,8 @@ struct VariantInitializer<Plane> { }; template <> -struct VariantInitializer<Quat> { - static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quat>(v); } +struct VariantInitializer<Quaternion> { + static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quaternion>(v); } }; template <> @@ -1075,7 +1082,7 @@ struct VariantInitializer<Basis> { }; template <> -struct VariantInitializer<Transform> { +struct VariantInitializer<Transform3D> { static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_transform(v); } }; @@ -1234,8 +1241,8 @@ struct VariantZeroAssigner<Plane> { }; template <> -struct VariantZeroAssigner<Quat> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quat(v) = Quat(); } +struct VariantZeroAssigner<Quaternion> { + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quaternion(v) = Quaternion(); } }; template <> @@ -1249,8 +1256,8 @@ struct VariantZeroAssigner<Basis> { }; template <> -struct VariantZeroAssigner<Transform> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform(); } +struct VariantZeroAssigner<Transform3D> { + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform3D(); } }; template <> diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 8cfa793c0e..10d0a83014 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -1395,7 +1395,7 @@ void Variant::_register_variant_operators() { 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); register_op<OperatorEvaluatorAdd<Vector3i, Vector3i, Vector3i>>(Variant::OP_ADD, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorAdd<Quat, Quat, Quat>>(Variant::OP_ADD, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorAdd<Quaternion, Quaternion, Quaternion>>(Variant::OP_ADD, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorAdd<Color, Color, Color>>(Variant::OP_ADD, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorAddArray>(Variant::OP_ADD, Variant::ARRAY, Variant::ARRAY); register_op<OperatorEvaluatorAppendArray<uint8_t>>(Variant::OP_ADD, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY); @@ -1416,7 +1416,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorSub<Vector2i, Vector2i, Vector2i>>(Variant::OP_SUBTRACT, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorSub<Vector3, Vector3, Vector3>>(Variant::OP_SUBTRACT, Variant::VECTOR3, Variant::VECTOR3); register_op<OperatorEvaluatorSub<Vector3i, Vector3i, Vector3i>>(Variant::OP_SUBTRACT, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorSub<Quat, Quat, Quat>>(Variant::OP_SUBTRACT, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorSub<Quaternion, Quaternion, Quaternion>>(Variant::OP_SUBTRACT, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorSub<Color, Color, Color>>(Variant::OP_SUBTRACT, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<int64_t, int64_t, int64_t>>(Variant::OP_MULTIPLY, Variant::INT, Variant::INT); @@ -1449,9 +1449,9 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorMul<Vector3i, Vector3i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT); register_op<OperatorEvaluatorMul<Vector3i, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); - register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT); - register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT); register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT); @@ -1465,25 +1465,25 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorXForm<Vector<Vector2>, Transform2D, Vector<Vector2>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::PACKED_VECTOR2_ARRAY); register_op<OperatorEvaluatorXFormInv<Vector<Vector2>, Vector<Vector2>, Transform2D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR2_ARRAY, Variant::TRANSFORM2D); - register_op<OperatorEvaluatorMul<Transform, Transform, Transform>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<Vector3, Transform, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::VECTOR3); - register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<::AABB, Transform, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::AABB); - register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::PACKED_VECTOR3_ARRAY); - register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, Transform3D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<Vector3, Transform3D, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::VECTOR3); + register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB); + register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY); + register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D); register_op<OperatorEvaluatorMul<Basis, Basis, Basis>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::BASIS); register_op<OperatorEvaluatorXForm<Vector3, Basis, Vector3>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::VECTOR3); register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Basis>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::BASIS); - register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT); - register_op<OperatorEvaluatorMul<Quat, int64_t, Quat>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT); - register_op<OperatorEvaluatorMul<Quat, double, Quat>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUAT); - register_op<OperatorEvaluatorXForm<Vector3, Quat, Vector3>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::VECTOR3); - register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quat>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUAT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); + register_op<OperatorEvaluatorMul<Quaternion, int64_t, Quaternion>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Quaternion, double, Quaternion>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUATERNION); + register_op<OperatorEvaluatorXForm<Vector3, Quaternion, Vector3>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::VECTOR3); + register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quaternion>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUATERNION); register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT); @@ -1516,8 +1516,8 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT); - register_op<OperatorEvaluatorDiv<Quat, Quat, double>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::FLOAT); - register_op<OperatorEvaluatorDiv<Quat, Quat, int64_t>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::INT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, double>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, int64_t>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::INT); register_op<OperatorEvaluatorDiv<Color, Color, Color>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorDiv<Color, Color, double>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::FLOAT); @@ -1544,10 +1544,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I); register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D); register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE); - register_op<OperatorEvaluatorStringModT<Quat>>(Variant::OP_MODULE, Variant::STRING, Variant::QUAT); + register_op<OperatorEvaluatorStringModT<Quaternion>>(Variant::OP_MODULE, Variant::STRING, Variant::QUATERNION); register_op<OperatorEvaluatorStringModT<::AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB); register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS); - register_op<OperatorEvaluatorStringModT<Transform>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM); + register_op<OperatorEvaluatorStringModT<Transform3D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM3D); register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR); register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME); @@ -1574,7 +1574,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNeg<Vector2i, Vector2i>>(Variant::OP_NEGATE, Variant::VECTOR2I, Variant::NIL); register_op<OperatorEvaluatorNeg<Vector3, Vector3>>(Variant::OP_NEGATE, Variant::VECTOR3, Variant::NIL); register_op<OperatorEvaluatorNeg<Vector3i, Vector3i>>(Variant::OP_NEGATE, Variant::VECTOR3I, Variant::NIL); - register_op<OperatorEvaluatorNeg<Quat, Quat>>(Variant::OP_NEGATE, Variant::QUAT, Variant::NIL); + register_op<OperatorEvaluatorNeg<Quaternion, Quaternion>>(Variant::OP_NEGATE, Variant::QUATERNION, Variant::NIL); register_op<OperatorEvaluatorNeg<Plane, Plane>>(Variant::OP_NEGATE, Variant::PLANE, Variant::NIL); register_op<OperatorEvaluatorNeg<Color, Color>>(Variant::OP_NEGATE, Variant::COLOR, Variant::NIL); @@ -1584,7 +1584,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorPos<Vector2i, Vector2i>>(Variant::OP_POSITIVE, Variant::VECTOR2I, Variant::NIL); register_op<OperatorEvaluatorPos<Vector3, Vector3>>(Variant::OP_POSITIVE, Variant::VECTOR3, Variant::NIL); register_op<OperatorEvaluatorPos<Vector3i, Vector3i>>(Variant::OP_POSITIVE, Variant::VECTOR3I, Variant::NIL); - register_op<OperatorEvaluatorPos<Quat, Quat>>(Variant::OP_POSITIVE, Variant::QUAT, Variant::NIL); + register_op<OperatorEvaluatorPos<Quaternion, Quaternion>>(Variant::OP_POSITIVE, Variant::QUATERNION, Variant::NIL); register_op<OperatorEvaluatorPos<Plane, Plane>>(Variant::OP_POSITIVE, Variant::PLANE, Variant::NIL); register_op<OperatorEvaluatorPos<Color, Color>>(Variant::OP_POSITIVE, Variant::COLOR, Variant::NIL); @@ -1612,10 +1612,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorEqual<Vector3i, Vector3i>>(Variant::OP_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorEqual<Transform2D, Transform2D>>(Variant::OP_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D); register_op<OperatorEvaluatorEqual<Plane, Plane>>(Variant::OP_EQUAL, Variant::PLANE, Variant::PLANE); - register_op<OperatorEvaluatorEqual<Quat, Quat>>(Variant::OP_EQUAL, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorEqual<Quaternion, Quaternion>>(Variant::OP_EQUAL, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorEqual<::AABB, ::AABB>>(Variant::OP_EQUAL, Variant::AABB, Variant::AABB); register_op<OperatorEvaluatorEqual<Basis, Basis>>(Variant::OP_EQUAL, Variant::BASIS, Variant::BASIS); - register_op<OperatorEvaluatorEqual<Transform, Transform>>(Variant::OP_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM); + register_op<OperatorEvaluatorEqual<Transform3D, Transform3D>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D); register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING); @@ -1658,10 +1658,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotEqual<Vector3i, Vector3i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorNotEqual<Transform2D, Transform2D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D); register_op<OperatorEvaluatorNotEqual<Plane, Plane>>(Variant::OP_NOT_EQUAL, Variant::PLANE, Variant::PLANE); - register_op<OperatorEvaluatorNotEqual<Quat, Quat>>(Variant::OP_NOT_EQUAL, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorNotEqual<Quaternion, Quaternion>>(Variant::OP_NOT_EQUAL, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorNotEqual<::AABB, ::AABB>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::AABB); register_op<OperatorEvaluatorNotEqual<Basis, Basis>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::BASIS); - register_op<OperatorEvaluatorNotEqual<Transform, Transform>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM); + register_op<OperatorEvaluatorNotEqual<Transform3D, Transform3D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D); register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING); @@ -1849,10 +1849,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInDictionaryHas<Vector3i>>(Variant::OP_IN, Variant::VECTOR3I, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Transform2D>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Plane>>(Variant::OP_IN, Variant::PLANE, Variant::DICTIONARY); - register_op<OperatorEvaluatorInDictionaryHas<Quat>>(Variant::OP_IN, Variant::QUAT, Variant::DICTIONARY); + register_op<OperatorEvaluatorInDictionaryHas<Quaternion>>(Variant::OP_IN, Variant::QUATERNION, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<::AABB>>(Variant::OP_IN, Variant::AABB, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Basis>>(Variant::OP_IN, Variant::BASIS, Variant::DICTIONARY); - register_op<OperatorEvaluatorInDictionaryHas<Transform>>(Variant::OP_IN, Variant::TRANSFORM, Variant::DICTIONARY); + register_op<OperatorEvaluatorInDictionaryHas<Transform3D>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Color>>(Variant::OP_IN, Variant::COLOR, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::DICTIONARY); @@ -1886,10 +1886,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInArrayFind<Vector3i, Array>>(Variant::OP_IN, Variant::VECTOR3I, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Transform2D, Array>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Plane, Array>>(Variant::OP_IN, Variant::PLANE, Variant::ARRAY); - register_op<OperatorEvaluatorInArrayFind<Quat, Array>>(Variant::OP_IN, Variant::QUAT, Variant::ARRAY); + register_op<OperatorEvaluatorInArrayFind<Quaternion, Array>>(Variant::OP_IN, Variant::QUATERNION, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<::AABB, Array>>(Variant::OP_IN, Variant::AABB, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Basis, Array>>(Variant::OP_IN, Variant::BASIS, Variant::ARRAY); - register_op<OperatorEvaluatorInArrayFind<Transform, Array>>(Variant::OP_IN, Variant::TRANSFORM, Variant::ARRAY); + register_op<OperatorEvaluatorInArrayFind<Transform3D, Array>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Color, Array>>(Variant::OP_IN, Variant::COLOR, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<StringName, Array>>(Variant::OP_IN, Variant::STRING_NAME, Variant::ARRAY); diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index edaeddbf27..751cb64c62 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -190,10 +190,13 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.type = TK_COLOR; return OK; } - case '@': { +#ifndef DISABLE_DEPRECATED + case '@': // Compatibility with 3.x StringNames. +#endif + case '&': { // StringName. cchar = p_stream->get_char(); if (cchar != '"') { - r_err_str = "Expected '\"' after '@'"; + r_err_str = "Expected '\"' after '&'"; r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } @@ -614,7 +617,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = Plane(args[0], args[1], args[2], args[3]); - } else if (id == "Quat") { + } else if (id == "Quaternion" || id == "Quat") { // "Quat" kept for compatibility Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); if (err) { @@ -626,7 +629,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - value = Quat(args[0], args[1], args[2], args[3]); + value = Quaternion(args[0], args[1], args[2], args[3]); } else if (id == "AABB" || id == "Rect3") { Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); @@ -653,7 +656,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); - } else if (id == "Transform") { + } else if (id == "Transform3D" || id == "Transform") { // "Transform" kept for compatibility with Godot <4. Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); if (err) { @@ -665,7 +668,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - value = Transform(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); + value = Transform3D(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); } else if (id == "Color") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -742,7 +745,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - REF ref = REF(Object::cast_to<Reference>(obj)); + REF ref = REF(Object::cast_to<RefCounted>(obj)); get_token(p_stream, token, line, r_err_str); if (token.type != TK_COMMA) { @@ -1454,9 +1457,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "AABB( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + " )"); } break; - case Variant::QUAT: { - Quat quat = p_variant; - p_store_string_func(p_store_string_ud, "Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )"); + case Variant::QUATERNION: { + Quaternion quaternion = p_variant; + p_store_string_func(p_store_string_ud, "Quaternion( " + rtosfix(quaternion.x) + ", " + rtosfix(quaternion.y) + ", " + rtosfix(quaternion.z) + ", " + rtosfix(quaternion.w) + " )"); } break; case Variant::TRANSFORM2D: { @@ -1489,9 +1492,9 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, s + " )"); } break; - case Variant::TRANSFORM: { - String s = "Transform( "; - Transform t = p_variant; + case Variant::TRANSFORM3D: { + String s = "Transform3D( "; + Transform3D t = p_variant; Basis &m3 = t.basis; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -1516,7 +1519,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::STRING_NAME: { String str = p_variant; - str = "@\"" + str.c_escape() + "\""; + str = "&\"" + str.c_escape() + "\""; p_store_string_func(p_store_string_ud, str); } break; diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 5703f0200c..05fc29b5e0 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -31,8 +31,8 @@ #ifndef VARIANT_PARSER_H #define VARIANT_PARSER_H +#include "core/io/file_access.h" #include "core/io/resource.h" -#include "core/os/file_access.h" #include "core/variant/variant.h" class VariantParser { diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 9ab8602782..ae2795f2fd 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -279,17 +279,17 @@ SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z) SETGET_STRUCT(Plane, Vector3, normal) SETGET_NUMBER_STRUCT(Plane, double, d) -SETGET_NUMBER_STRUCT(Quat, double, x) -SETGET_NUMBER_STRUCT(Quat, double, y) -SETGET_NUMBER_STRUCT(Quat, double, z) -SETGET_NUMBER_STRUCT(Quat, double, w) +SETGET_NUMBER_STRUCT(Quaternion, double, x) +SETGET_NUMBER_STRUCT(Quaternion, double, y) +SETGET_NUMBER_STRUCT(Quaternion, double, z) +SETGET_NUMBER_STRUCT(Quaternion, double, w) SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0) SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1) SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2) -SETGET_STRUCT(Transform, Basis, basis) -SETGET_STRUCT(Transform, Vector3, origin) +SETGET_STRUCT(Transform3D, Basis, basis) +SETGET_STRUCT(Transform3D, Vector3, origin) SETGET_NUMBER_STRUCT(Color, double, r) SETGET_NUMBER_STRUCT(Color, double, g) @@ -374,17 +374,17 @@ void register_named_setters_getters() { REGISTER_MEMBER(Plane, d); REGISTER_MEMBER(Plane, normal); - REGISTER_MEMBER(Quat, x); - REGISTER_MEMBER(Quat, y); - REGISTER_MEMBER(Quat, z); - REGISTER_MEMBER(Quat, w); + REGISTER_MEMBER(Quaternion, x); + REGISTER_MEMBER(Quaternion, y); + REGISTER_MEMBER(Quaternion, z); + REGISTER_MEMBER(Quaternion, w); REGISTER_MEMBER(Basis, x); REGISTER_MEMBER(Basis, y); REGISTER_MEMBER(Basis, z); - REGISTER_MEMBER(Transform, basis); - REGISTER_MEMBER(Transform, origin); + REGISTER_MEMBER(Transform3D, basis); + REGISTER_MEMBER(Transform3D, origin); REGISTER_MEMBER(Color, r); REGISTER_MEMBER(Color, g); @@ -975,7 +975,7 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quat, double, real_t, 4) +INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quaternion, double, real_t, 4) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4) INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3) @@ -1037,7 +1037,7 @@ void register_indexed_setters_getters() { REGISTER_INDEXED_MEMBER(Vector2i); REGISTER_INDEXED_MEMBER(Vector3); REGISTER_INDEXED_MEMBER(Vector3i); - REGISTER_INDEXED_MEMBER(Quat); + REGISTER_INDEXED_MEMBER(Quaternion); REGISTER_INDEXED_MEMBER(Color); REGISTER_INDEXED_MEMBER(Transform2D); REGISTER_INDEXED_MEMBER(Basis); @@ -1453,7 +1453,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } @@ -1680,7 +1680,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } @@ -1865,7 +1865,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { return Variant(); } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_valid = false; return Variant(); } @@ -2135,10 +2135,10 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c); } return; - case QUAT: { - Quat empty_rot; - const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem); - const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem); + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem); + const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem); r_dst = *qa * empty_rot.slerp(*qb, c); } return; @@ -2295,8 +2295,8 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = a; } return; - case QUAT: { - r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c); + case QUATERNION: { + r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c); } return; case AABB: { @@ -2304,11 +2304,11 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case BASIS: { - r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis; + r_dst = Transform3D(*a._data._basis).interpolate_with(Transform3D(*b._data._basis), c).basis; } return; - case TRANSFORM: { - r_dst = a._data._transform->interpolate_with(*b._data._transform, c); + case TRANSFORM3D: { + r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c); } return; case COLOR: { diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 553f2b23a2..5d1efb4166 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/io/marshalls.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/templates/oa_hash_map.h" #include "core/variant/binder_common.h" |