diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/bind/core_bind.cpp | 16 | ||||
| -rw-r--r-- | core/class_db.cpp | 2 | ||||
| -rw-r--r-- | core/error_macros.h | 10 | ||||
| -rw-r--r-- | core/image.cpp | 53 | ||||
| -rw-r--r-- | core/image.h | 2 | ||||
| -rw-r--r-- | core/input_map.cpp | 67 | ||||
| -rw-r--r-- | core/input_map.h | 7 | ||||
| -rw-r--r-- | core/io/http_client.cpp | 6 | ||||
| -rw-r--r-- | core/io/image_loader.cpp | 2 | ||||
| -rw-r--r-- | core/io/pck_packer.cpp | 8 | ||||
| -rw-r--r-- | core/io/resource_saver.cpp | 2 | ||||
| -rw-r--r-- | core/math/math_funcs.h | 4 | ||||
| -rw-r--r-- | core/math/matrix3.cpp | 63 | ||||
| -rw-r--r-- | core/math/matrix3.h | 15 | ||||
| -rw-r--r-- | core/math/quick_hull.cpp | 2 | ||||
| -rw-r--r-- | core/math/transform.cpp | 4 | ||||
| -rw-r--r-- | core/node_path.cpp | 3 | ||||
| -rw-r--r-- | core/os/input.cpp | 3 | ||||
| -rw-r--r-- | core/os/input.h | 1 | ||||
| -rw-r--r-- | core/os/input_event.cpp | 85 | ||||
| -rw-r--r-- | core/os/input_event.h | 22 | ||||
| -rw-r--r-- | core/project_settings.cpp | 28 | ||||
| -rw-r--r-- | core/project_settings.h | 2 | ||||
| -rw-r--r-- | core/string_db.cpp | 13 | ||||
| -rw-r--r-- | core/string_db.h | 1 | ||||
| -rw-r--r-- | core/ustring.cpp | 152 | ||||
| -rw-r--r-- | core/ustring.h | 11 | ||||
| -rw-r--r-- | core/variant.cpp | 6 | ||||
| -rw-r--r-- | core/variant_call.cpp | 10 | ||||
| -rw-r--r-- | core/variant_op.cpp | 21 |
30 files changed, 477 insertions, 144 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 85793f127..a51f2397c 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -639,8 +639,8 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { 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]) : 0); - unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) - 1 : 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) @@ -660,15 +660,15 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { ERR_EXPLAIN("Invalid hour value of: " + itos(hour)); ERR_FAIL_COND_V(hour > 23, 0); - ERR_EXPLAIN("Invalid month value of: " + itos(month + 1)); - ERR_FAIL_COND_V(month + 1 > 12, 0); + ERR_EXPLAIN("Invalid month value of: " + itos(month)); + ERR_FAIL_COND_V(month > 12 || month == 0, 0); // Do this check after month is tested as valid - ERR_EXPLAIN("Invalid day value of: " + itos(day) + " which is larger than " + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month])); - ERR_FAIL_COND_V(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month], 0); + ERR_EXPLAIN("Invalid day value of: " + itos(day) + " which is larger than " + itos(MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]) + " or 0"); + ERR_FAIL_COND_V(day > MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1] || day == 0, 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] * SECONDS_PER_DAY; + uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; uint64_t SECONDS_FROM_YEARS_PAST = 0; for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { @@ -2413,7 +2413,7 @@ _Thread::_Thread() { _Thread::~_Thread() { if (active) { - ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running.."); + ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running..."); } ERR_FAIL_COND(active == true); } diff --git a/core/class_db.cpp b/core/class_db.cpp index 92aa131e2..08c1ade67 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -254,11 +254,13 @@ HashMap<StringName, StringName, StringNameHasher> ClassDB::compat_classes; ClassDB::ClassInfo::ClassInfo() { + api = API_NONE; creation_func = NULL; inherits_ptr = NULL; disabled = false; exposed = false; } + ClassDB::ClassInfo::~ClassInfo() { } diff --git a/core/error_macros.h b/core/error_macros.h index b8d0c7e0c..168b2e06f 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -311,4 +311,14 @@ extern bool _err_error_exists; _err_error_exists = false; \ } +#define WARN_DEPRECATED \ + { \ + static bool warning_shown=false;\ + if (!warning_shown) {\ + _err_print_error(FUNCTION_STR, __FILE__, __LINE__,"This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \ + _err_error_exists = false; \ + warning_shown=true;\ + }\ + } + #endif diff --git a/core/image.cpp b/core/image.cpp index 2ac8ffea5..58f49d69e 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -366,6 +366,8 @@ int Image::get_mipmap_count() const { template <uint32_t read_bytes, bool read_alpha, uint32_t write_bytes, bool write_alpha, bool read_gray, bool write_gray> static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p_dst) { + uint32_t max_bytes = MAX(read_bytes, write_bytes); + for (int y = 0; y < p_height; y++) { for (int x = 0; x < p_width; x++) { @@ -379,7 +381,8 @@ static void _convert(int p_width, int p_height, const uint8_t *p_src, uint8_t *p rgba[1] = rofs[0]; rgba[2] = rofs[0]; } else { - for (uint32_t i = 0; i < MAX(read_bytes, write_bytes); i++) { + + for (uint32_t i = 0; i < max_bytes; i++) { rgba[i] = (i < read_bytes) ? rofs[i] : 0; } @@ -937,7 +940,7 @@ bool Image::_can_modify(Format p_format) const { return p_format <= FORMAT_RGBE9995; } -template <int CC> +template <int CC, bool renormalize> static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t p_width, uint32_t p_height) { //fast power of 2 mipmap generation @@ -963,6 +966,19 @@ static void _generate_po2_mipmap(const uint8_t *p_src, uint8_t *p_dst, uint32_t dst_ptr[j] = val >> 2; } + if (renormalize) { + Vector3 n(dst_ptr[0] / 255.0, dst_ptr[1] / 255.0, dst_ptr[2] / 255.0); + n *= 2.0; + n -= Vector3(1, 1, 1); + n.normalize(); + n += Vector3(1, 1, 1); + n *= 0.5; + n *= 255; + dst_ptr[0] = CLAMP(int(n.x), 0, 255); + dst_ptr[1] = CLAMP(int(n.y), 0, 255); + dst_ptr[2] = CLAMP(int(n.z), 0, 255); + } + dst_ptr += CC; rup_ptr += CC * 2; rdown_ptr += CC * 2; @@ -1045,11 +1061,11 @@ void Image::shrink_x2() { switch (format) { case FORMAT_L8: - case FORMAT_R8: _generate_po2_mipmap<1>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_LA8: _generate_po2_mipmap<2>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_RG8: _generate_po2_mipmap<2>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_RGB8: _generate_po2_mipmap<3>(r.ptr(), w.ptr(), width, height); break; - case FORMAT_RGBA8: _generate_po2_mipmap<4>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_R8: _generate_po2_mipmap<1, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_LA8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_RG8: _generate_po2_mipmap<2, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_RGB8: _generate_po2_mipmap<3, false>(r.ptr(), w.ptr(), width, height); break; + case FORMAT_RGBA8: _generate_po2_mipmap<4, false>(r.ptr(), w.ptr(), width, height); break; default: {} } } @@ -1060,7 +1076,7 @@ void Image::shrink_x2() { } } -Error Image::generate_mipmaps() { +Error Image::generate_mipmaps(bool p_renormalize) { if (!_can_modify(format)) { ERR_EXPLAIN("Cannot generate mipmaps in indexed, compressed or custom image formats."); @@ -1089,11 +1105,22 @@ Error Image::generate_mipmaps() { switch (format) { case FORMAT_L8: - case FORMAT_R8: _generate_po2_mipmap<1>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; + case FORMAT_R8: _generate_po2_mipmap<1, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; case FORMAT_LA8: - case FORMAT_RG8: _generate_po2_mipmap<2>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; - case FORMAT_RGB8: _generate_po2_mipmap<3>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; - case FORMAT_RGBA8: _generate_po2_mipmap<4>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; + case FORMAT_RG8: _generate_po2_mipmap<2, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); break; + case FORMAT_RGB8: + if (p_renormalize) + _generate_po2_mipmap<3, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + else + _generate_po2_mipmap<3, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + + break; + case FORMAT_RGBA8: + if (p_renormalize) + _generate_po2_mipmap<4, true>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + else + _generate_po2_mipmap<4, false>(&wp[prev_ofs], &wp[ofs], prev_w, prev_h); + break; default: {} } @@ -2217,7 +2244,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("crop", "width", "height"), &Image::crop); ClassDB::bind_method(D_METHOD("flip_x"), &Image::flip_x); ClassDB::bind_method(D_METHOD("flip_y"), &Image::flip_y); - ClassDB::bind_method(D_METHOD("generate_mipmaps"), &Image::generate_mipmaps); + ClassDB::bind_method(D_METHOD("generate_mipmaps", "renormalize"), &Image::generate_mipmaps, DEFVAL(false)); ClassDB::bind_method(D_METHOD("clear_mipmaps"), &Image::clear_mipmaps); ClassDB::bind_method(D_METHOD("create", "width", "height", "use_mipmaps", "format"), &Image::_create_empty); diff --git a/core/image.h b/core/image.h index 17477d88e..3c43e4995 100644 --- a/core/image.h +++ b/core/image.h @@ -217,7 +217,7 @@ public: /** * Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1) */ - Error generate_mipmaps(); + Error generate_mipmaps(bool p_renormalize = false); void clear_mipmaps(); diff --git a/core/input_map.cpp b/core/input_map.cpp index ea724d259..67c0e4eb0 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -41,9 +41,10 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("has_action", "action"), &InputMap::has_action); ClassDB::bind_method(D_METHOD("get_actions"), &InputMap::_get_actions); - ClassDB::bind_method(D_METHOD("add_action", "action"), &InputMap::add_action); + ClassDB::bind_method(D_METHOD("add_action", "action", "deadzone"), &InputMap::add_action, DEFVAL(0.5f)); ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); + ClassDB::bind_method(D_METHOD("action_set_deadzone", "deadzone"), &InputMap::action_set_deadzone); ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event); ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); @@ -52,12 +53,13 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("load_from_globals"), &InputMap::load_from_globals); } -void InputMap::add_action(const StringName &p_action) { +void InputMap::add_action(const StringName &p_action, float p_deadzone) { ERR_FAIL_COND(input_map.has(p_action)); input_map[p_action] = Action(); static int last_id = 1; input_map[p_action].id = last_id; + input_map[p_action].deadzone = p_deadzone; last_id++; } @@ -96,9 +98,9 @@ List<StringName> InputMap::get_actions() const { return actions; } -List<Ref<InputEvent> >::Element *InputMap::_find_event(List<Ref<InputEvent> > &p_list, const Ref<InputEvent> &p_event, bool p_action_test) const { +List<Ref<InputEvent> >::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength) const { - for (List<Ref<InputEvent> >::Element *E = p_list.front(); E; E = E->next()) { + for (List<Ref<InputEvent> >::Element *E = p_action.inputs.front(); E; E = E->next()) { const Ref<InputEvent> e = E->get(); @@ -106,9 +108,11 @@ List<Ref<InputEvent> >::Element *InputMap::_find_event(List<Ref<InputEvent> > &p // continue; int device = e->get_device(); - if (device == ALL_DEVICES || device == p_event->get_device()) - if (e->action_match(p_event)) + if (device == ALL_DEVICES || device == p_event->get_device()) { + if (e->action_match(p_event, p_pressed, p_strength, p_action.deadzone)) { return E; + } + } } return NULL; @@ -119,11 +123,18 @@ bool InputMap::has_action(const StringName &p_action) const { return input_map.has(p_action); } +void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) { + + ERR_FAIL_COND(!input_map.has(p_action)); + + input_map[p_action].deadzone = p_deadzone; +} + void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); ERR_FAIL_COND(!input_map.has(p_action)); - if (_find_event(input_map[p_action].inputs, p_event)) + if (_find_event(input_map[p_action], p_event)) return; //already gots input_map[p_action].inputs.push_back(p_event); @@ -132,14 +143,14 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND_V(!input_map.has(p_action), false); - return (_find_event(input_map[p_action].inputs, p_event) != NULL); + return (_find_event(input_map[p_action], p_event) != NULL); } void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND(!input_map.has(p_action)); - List<Ref<InputEvent> >::Element *E = _find_event(input_map[p_action].inputs, p_event); + List<Ref<InputEvent> >::Element *E = _find_event(input_map[p_action], p_event); if (E) input_map[p_action].inputs.erase(E); } @@ -168,19 +179,33 @@ const List<Ref<InputEvent> > *InputMap::get_action_list(const StringName &p_acti } bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const { + return event_get_action_status(p_event, p_action); +} +bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength) const { Map<StringName, Action>::Element *E = input_map.find(p_action); if (!E) { ERR_EXPLAIN("Request for nonexistent InputMap action: " + String(p_action)); ERR_FAIL_COND_V(!E, false); } - Ref<InputEventAction> iea = p_event; - if (iea.is_valid()) { - return iea->get_action() == p_action; + Ref<InputEventAction> input_event_action = p_event; + if (input_event_action.is_valid()) { + return input_event_action->get_action() == p_action; } - return _find_event(E->get().inputs, p_event, true) != NULL; + bool pressed; + float strength; + List<Ref<InputEvent> >::Element *event = _find_event(E->get(), p_event, &pressed, &strength); + if (event != NULL) { + if (p_pressed != NULL) + *p_pressed = pressed; + if (p_strength != NULL) + *p_strength = strength; + return true; + } else { + return false; + } } const Map<StringName, InputMap::Action> &InputMap::get_action_map() const { @@ -202,16 +227,16 @@ void InputMap::load_from_globals() { String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length()); - add_action(name); - - Array va = ProjectSettings::get_singleton()->get(pi.name); - - for (int i = 0; i < va.size(); i++) { + Dictionary action = ProjectSettings::get_singleton()->get(pi.name); + float deadzone = action.has("deadzone") ? (float)action["deadzone"] : 0.5f; + Array events = action["events"]; - Ref<InputEvent> ie = va[i]; - if (ie.is_null()) + add_action(name, deadzone); + for (int i = 0; i < events.size(); i++) { + Ref<InputEvent> event = events[i]; + if (event.is_null()) continue; - action_add_event(name, ie); + action_add_event(name, event); } } } diff --git a/core/input_map.h b/core/input_map.h index 9f3c13c2c..f497a2b86 100644 --- a/core/input_map.h +++ b/core/input_map.h @@ -46,6 +46,7 @@ public: struct Action { int id; + float deadzone; List<Ref<InputEvent> > inputs; }; @@ -54,7 +55,7 @@ private: mutable Map<StringName, Action> input_map; - List<Ref<InputEvent> >::Element *_find_event(List<Ref<InputEvent> > &p_list, const Ref<InputEvent> &p_event, bool p_action_test = false) const; + List<Ref<InputEvent> >::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = NULL, float *p_strength = NULL) const; Array _get_action_list(const StringName &p_action); Array _get_actions(); @@ -67,15 +68,17 @@ public: bool has_action(const StringName &p_action) const; List<StringName> get_actions() const; - void add_action(const StringName &p_action); + void add_action(const StringName &p_action, float p_deadzone = 0.5); void erase_action(const StringName &p_action); + void action_set_deadzone(const StringName &p_action, float p_deadzone); void action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event); bool action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event); void action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event); const List<Ref<InputEvent> > *get_action_list(const StringName &p_action); bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const; + bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = NULL, float *p_strength = NULL) const; const Map<StringName, Action> &get_action_map() const; void load_from_globals(); diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index c787b7ec4..9e301ccac 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -618,14 +618,14 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { String query = ""; Array keys = p_dict.keys(); for (int i = 0; i < keys.size(); ++i) { - String encoded_key = String(keys[i]).percent_encode(); + String encoded_key = String(keys[i]).http_escape(); Variant value = p_dict[keys[i]]; switch (value.get_type()) { case Variant::ARRAY: { // Repeat the key with every values Array values = value; for (int j = 0; j < values.size(); ++j) { - query += "&" + encoded_key + "=" + String(values[j]).percent_encode(); + query += "&" + encoded_key + "=" + String(values[j]).http_escape(); } break; } @@ -636,7 +636,7 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { } default: { // Add the key-value pair - query += "&" + encoded_key + "=" + String(value).percent_encode(); + query += "&" + encoded_key + "=" + String(value).http_escape(); } } } diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 999c9a8ca..8ebd9d6cd 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -37,7 +37,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const { get_recognized_extensions(&extensions); for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - if (E->get().nocasecmp_to(p_extension.get_extension()) == 0) + if (E->get().nocasecmp_to(p_extension) == 0) return true; } diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 596060221..b6377662d 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "pck_packer.h" - #include "core/os/file_access.h" +#include "version.h" static uint64_t _align(uint64_t p_n, int p_alignment) { @@ -70,9 +70,9 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) { alignment = p_alignment; file->store_32(0x43504447); // MAGIC - file->store_32(0); // # version - file->store_32(0); // # major - file->store_32(0); // # minor + file->store_32(1); // # version + file->store_32(VERSION_MAJOR); // # major + file->store_32(VERSION_MINOR); // # minor file->store_32(0); // # revision for (int i = 0; i < 16; i++) { diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 609dd7e93..3dcd94880 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -56,7 +56,7 @@ Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - if (E->get().nocasecmp_to(extension.get_extension()) == 0) + if (E->get().nocasecmp_to(extension) == 0) recognized = true; } diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 26e87f009..20001bb9a 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -215,11 +215,11 @@ public: } static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { double rng = max - min; - return min + (value - min) - (rng * Math::floor((value - min) / rng)); + return value - (rng * Math::floor((value - min) / rng)); } static _ALWAYS_INLINE_ float wrapf(float value, float min, float max) { float rng = max - min; - return min + (value - min) - (rng * Math::floor((value - min) / rng)); + return value - (rng * Math::floor((value - min) / rng)); } // double only, as these functions are mainly used by the editor and not performance-critical, diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp index 189b1ef9b..b0b05d1ec 100644 --- a/core/math/matrix3.cpp +++ b/core/math/matrix3.cpp @@ -254,7 +254,7 @@ void Basis::set_scale(const Vector3 &p_scale) { set_axis(2, get_axis(2).normalized() * p_scale.z); } -Vector3 Basis::get_scale() const { +Vector3 Basis::get_scale_abs() const { return Vector3( Vector3(elements[0][0], elements[1][0], elements[2][0]).length(), @@ -262,7 +262,13 @@ Vector3 Basis::get_scale() const { Vector3(elements[0][2], elements[1][2], elements[2][2]).length()); } -Vector3 Basis::get_signed_scale() const { +Vector3 Basis::get_scale_local() const { + real_t det_sign = determinant() > 0 ? 1 : -1; + return det_sign * Vector3(elements[0].length(), elements[1].length(), elements[2].length()); +} + +// get_scale works with get_rotation, use get_scale_abs if you need to enforce positive signature. +Vector3 Basis::get_scale() const { // FIXME: We are assuming M = R.S (R is rotation and S is scaling), and use polar decomposition to extract R and S. // A polar decomposition is M = O.P, where O is an orthogonal matrix (meaning rotation and reflection) and // P is a positive semi-definite matrix (meaning it contains absolute values of scaling along its diagonal). @@ -342,6 +348,14 @@ void Basis::rotate(const Vector3 &p_euler) { *this = rotated(p_euler); } +Basis Basis::rotated(const Quat &p_quat) const { + return Basis(p_quat) * (*this); +} + +void Basis::rotate(const Quat &p_quat) { + *this = rotated(p_quat); +} + // TODO: rename this to get_rotation_euler Vector3 Basis::get_rotation() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, @@ -371,6 +385,22 @@ void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { m.get_axis_angle(p_axis, p_angle); } +void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) 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. + Basis m = transposed(); + m.orthonormalize(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + m.get_axis_angle(p_axis, p_angle); + p_angle = -p_angle; +} + // get_euler_xyz returns a vector containing the Euler angles in the format // (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last // (following the convention they are commonly defined in the literature). @@ -767,3 +797,32 @@ void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { elements[2][1] = p_axis.y * p_axis.z * (1.0 - cosine) + p_axis.x * sine; elements[2][2] = axis_sq.z + cosine * (1.0 - axis_sq.z); } + +void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_axis, p_phi); +} + +void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_euler); +} + +void Basis::set_quat_scale(const Quat &p_quat, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_quat); +} + +void Basis::set_diagonal(const Vector3 p_diag) { + elements[0][0] = p_diag.x; + elements[0][1] = 0; + elements[0][2] = 0; + + elements[1][0] = 0; + elements[1][1] = p_diag.y; + elements[1][2] = 0; + + elements[2][0] = 0; + elements[2][1] = 0; + elements[2][2] = p_diag.z; +} diff --git a/core/math/matrix3.h b/core/math/matrix3.h index c42643572..fd383fc67 100644 --- a/core/math/matrix3.h +++ b/core/math/matrix3.h @@ -81,8 +81,12 @@ 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; + Vector3 get_rotation() 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; Vector3 rotref_posscale_decomposition(Basis &rotref) const; @@ -108,7 +112,12 @@ public: void set_scale(const Vector3 &p_scale); Vector3 get_scale() const; - Vector3 get_signed_scale() const; + Vector3 get_scale_abs() const; + Vector3 get_scale_local() const; + + 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); // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { @@ -140,6 +149,8 @@ public: int get_orthogonal_index() const; void set_orthogonal_index(int p_index); + void set_diagonal(const Vector3 p_diag); + bool is_orthogonal() const; bool is_diagonal() const; bool is_rotation() const; @@ -219,6 +230,8 @@ public: Basis(const Quat &p_quat) { set_quat(p_quat); }; Basis(const Vector3 &p_euler) { set_euler(p_euler); } Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); } + Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); } + Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) { elements[0] = row0; diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index 102e454e0..fc9041741 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -74,7 +74,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me int longest_axis = aabb.get_longest_axis_index(); //first two vertices are the most distant - int simplex[4]; + int simplex[4] = { 0 }; { real_t max = 0, min = 0; diff --git a/core/math/transform.cpp b/core/math/transform.cpp index f727d00e3..7cd186ca6 100644 --- a/core/math/transform.cpp +++ b/core/math/transform.cpp @@ -119,11 +119,11 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) /* not sure if very "efficient" but good enough? */ - Vector3 src_scale = basis.get_signed_scale(); + Vector3 src_scale = basis.get_scale(); Quat src_rot = basis.orthonormalized(); Vector3 src_loc = origin; - Vector3 dst_scale = p_transform.basis.get_signed_scale(); + Vector3 dst_scale = p_transform.basis.get_scale(); Quat dst_rot = p_transform.basis; Vector3 dst_loc = p_transform.origin; diff --git a/core/node_path.cpp b/core/node_path.cpp index cd7ad7753..64983fc09 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -264,8 +264,9 @@ NodePath NodePath::get_as_property_path() const { Vector<StringName> new_path = data->subpath; String initial_subname = data->path[0]; + for (size_t i = 1; i < data->path.size(); i++) { - initial_subname += i == 0 ? data->path[i].operator String() : "/" + data->path[i]; + initial_subname += "/" + data->path[i]; } new_path.insert(0, initial_subname); diff --git a/core/os/input.cpp b/core/os/input.cpp index e8a635e1b..a5b0f91e6 100644 --- a/core/os/input.cpp +++ b/core/os/input.cpp @@ -57,6 +57,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed); ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed); ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released); + ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength); ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false)); ClassDB::bind_method(D_METHOD("remove_joy_mapping", "guid"), &Input::remove_joy_mapping); ClassDB::bind_method(D_METHOD("joy_connection_changed", "device", "connected", "name", "guid"), &Input::joy_connection_changed); @@ -119,7 +120,7 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S #ifdef TOOLS_ENABLED String pf = p_function; - if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released")) { + if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || pf == "is_action_just_pressed" || pf == "is_action_just_released" || pf == "get_action_strength")) { List<PropertyInfo> pinfo; ProjectSettings::get_singleton()->get_property_list(&pinfo); diff --git a/core/os/input.h b/core/os/input.h index b0d72a6d5..001871c5d 100644 --- a/core/os/input.h +++ b/core/os/input.h @@ -85,6 +85,7 @@ public: virtual bool is_action_pressed(const StringName &p_action) const = 0; virtual bool is_action_just_pressed(const StringName &p_action) const = 0; virtual bool is_action_just_released(const StringName &p_action) const = 0; + virtual float get_action_strength(const StringName &p_action) const = 0; virtual float get_joy_axis(int p_device, int p_axis) const = 0; virtual String get_joy_name(int p_idx) = 0; diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index b9607632f..4ebb821a2 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -41,11 +41,6 @@ int InputEvent::get_device() const { return device; } -bool InputEvent::is_pressed() const { - - return false; -} - bool InputEvent::is_action(const StringName &p_action) const { return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action); @@ -53,11 +48,29 @@ bool InputEvent::is_action(const StringName &p_action) const { bool InputEvent::is_action_pressed(const StringName &p_action) const { - return (is_pressed() && !is_echo() && is_action(p_action)); + bool pressed; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); + return valid && pressed && !is_echo(); } + bool InputEvent::is_action_released(const StringName &p_action) const { - return (!is_pressed() && is_action(p_action)); + bool pressed; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); + return valid && !pressed; +} + +float InputEvent::get_action_strength(const StringName &p_action) const { + + bool pressed; + float strength; + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed, &strength); + return valid ? strength : 0.0f; +} + +bool InputEvent::is_pressed() const { + + return false; } bool InputEvent::is_echo() const { @@ -75,7 +88,7 @@ String InputEvent::as_text() const { return String(); } -bool InputEvent::action_match(const Ref<InputEvent> &p_event) const { +bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { return false; } @@ -95,15 +108,16 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device); ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); - ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &InputEvent::is_action_pressed); ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); + ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength); + + ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo); ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text); - ClassDB::bind_method(D_METHOD("action_match", "event"), &InputEvent::action_match); ClassDB::bind_method(D_METHOD("shortcut_match", "event"), &InputEvent::shortcut_match); ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type); @@ -281,7 +295,7 @@ String InputEventKey::as_text() const { return kc; } -bool InputEventKey::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventKey> key = p_event; if (key.is_null()) @@ -290,7 +304,14 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event) const { uint32_t code = get_scancode_with_modifiers(); uint32_t event_code = key->get_scancode_with_modifiers(); - return get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); + bool match = get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); + if (match) { + if (p_pressed != NULL) + *p_pressed = key->is_pressed(); + if (p_strength != NULL) + *p_strength = (*p_pressed) ? 1.0f : 0.0f; + } + return match; } bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const { @@ -446,13 +467,21 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co return mb; } -bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventMouseButton> mb = p_event; if (mb.is_null()) return false; - return mb->button_index == button_index; + bool match = mb->button_index == button_index; + if (match) { + if (p_pressed != NULL) + *p_pressed = mb->is_pressed(); + if (p_strength != NULL) + *p_strength = (*p_pressed) ? 1.0f : 0.0f; + } + + return match; } String InputEventMouseButton::as_text() const { @@ -610,6 +639,7 @@ void InputEventJoypadMotion::set_axis_value(float p_value) { axis_value = p_value; } + float InputEventJoypadMotion::get_axis_value() const { return axis_value; @@ -617,16 +647,25 @@ float InputEventJoypadMotion::get_axis_value() const { bool InputEventJoypadMotion::is_pressed() const { - return Math::abs(axis_value) > 0.5f; + return Math::abs(axis_value) >= 0.5f; } -bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventJoypadMotion> jm = p_event; if (jm.is_null()) return false; - return (axis == jm->axis && ((axis_value < 0) == (jm->axis_value < 0) || jm->axis_value == 0)); + bool match = (axis == jm->axis); // Matches even if not in the same direction, but returns a "not pressed" event. + if (match) { + bool same_direction = (((axis_value < 0) == (jm->axis_value < 0)) || jm->axis_value == 0); + bool pressed = same_direction ? Math::abs(jm->get_axis_value()) >= p_deadzone : false; + if (p_pressed != NULL) + *p_pressed = pressed; + if (p_strength != NULL) + *p_strength = pressed ? CLAMP(Math::inverse_lerp(p_deadzone, 1.0f, Math::abs(jm->get_axis_value())), 0.0f, 1.0f) : 0.0f; + } + return match; } String InputEventJoypadMotion::as_text() const { @@ -681,13 +720,21 @@ float InputEventJoypadButton::get_pressure() const { return pressure; } -bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event) const { +bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const { Ref<InputEventJoypadButton> jb = p_event; if (jb.is_null()) return false; - return button_index == jb->button_index; + bool match = button_index == jb->button_index; + if (match) { + if (p_pressed != NULL) + *p_pressed = jb->is_pressed(); + if (p_strength != NULL) + *p_strength = (*p_pressed) ? 1.0f : 0.0f; + } + + return match; } String InputEventJoypadButton::as_text() const { diff --git a/core/os/input_event.h b/core/os/input_event.h index 0a33ab18a..037649ed6 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -154,16 +154,21 @@ public: void set_device(int p_device); int get_device() const; + bool is_action(const StringName &p_action) const; + bool is_action_pressed(const StringName &p_action) const; + bool is_action_released(const StringName &p_action) const; + float get_action_strength(const StringName &p_action) const; + + // To be removed someday, since they do not make sense for all events virtual bool is_pressed() const; - virtual bool is_action(const StringName &p_action) const; - virtual bool is_action_pressed(const StringName &p_action) const; - virtual bool is_action_released(const StringName &p_action) const; virtual bool is_echo() const; + // ...-. + virtual String as_text() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const; @@ -244,7 +249,7 @@ public: uint32_t get_scancode_with_modifiers() const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const { return true; } @@ -305,7 +310,7 @@ public: bool is_doubleclick() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; @@ -352,7 +357,8 @@ public: float get_axis_value() const; virtual bool is_pressed() const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; @@ -379,7 +385,7 @@ public: void set_pressure(float p_pressure); float get_pressure() const; - virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float p_deadzone) const; virtual bool is_action_type() const { return true; } virtual String as_text() const; diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 20d91e794..ac4a4b7d1 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -42,7 +42,7 @@ #include "variant_parser.h" #include <zlib.h> -#define FORMAT_VERSION 3 +#define FORMAT_VERSION 4 ProjectSettings *ProjectSettings::singleton = NULL; @@ -262,6 +262,23 @@ bool ProjectSettings::_load_resource_pack(const String &p_pack) { return true; } +void ProjectSettings::_convert_to_last_version() { + if (!has_setting("config_version") || (int)get_setting("config_version") <= 3) { + + // Converts the actions from array to dictionary (array of events to dictionary with deadzone + events) + for (Map<StringName, ProjectSettings::VariantContainer>::Element *E = props.front(); E; E = E->next()) { + Variant value = E->get().variant; + if (String(E->key()).begins_with("input/") && value.get_type() == Variant::ARRAY) { + Array array = value; + Dictionary action; + action["deadzone"] = Variant(0.5f); + action["events"] = array; + E->get().variant = action; + } + } + } +} + Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) { //If looking for files in network, just use network! @@ -390,6 +407,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + _convert_to_last_version(); + return OK; } @@ -797,12 +816,11 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust Variant _GLOBAL_DEF(const String &p_var, const Variant &p_default) { Variant ret; - if (ProjectSettings::get_singleton()->has_setting(p_var)) { - ret = ProjectSettings::get_singleton()->get(p_var); - } else { + if (!ProjectSettings::get_singleton()->has_setting(p_var)) { ProjectSettings::get_singleton()->set(p_var, p_default); - ret = p_default; } + ret = ProjectSettings::get_singleton()->get(p_var); + ProjectSettings::get_singleton()->set_initial_value(p_var, p_default); ProjectSettings::get_singleton()->set_builtin_order(p_var); return ret; diff --git a/core/project_settings.h b/core/project_settings.h index 9b51bc3ac..b01e7855a 100644 --- a/core/project_settings.h +++ b/core/project_settings.h @@ -102,6 +102,8 @@ protected: Error _save_custom_bnd(const String &p_file); + void _convert_to_last_version(); + bool _load_resource_pack(const String &p_pack); void _add_property_info_bind(const Dictionary &p_info); diff --git a/core/string_db.cpp b/core/string_db.cpp index 6e1f88775..2475cbe3e 100644 --- a/core/string_db.cpp +++ b/core/string_db.cpp @@ -164,21 +164,14 @@ void StringName::operator=(const StringName &p_name) { _data = p_name._data; } } -/* was inlined -StringName::operator String() const { - if (_data) - return _data->get_name(); - - return ""; -} -*/ StringName::StringName(const StringName &p_name) { - ERR_FAIL_COND(!configured); _data = NULL; - if (p_name._data && p_name._data->refcount.ref()) { + ERR_FAIL_COND(!configured); + + if (p_name._data && p_name._data->refcount.ref()) { _data = p_name._data; } } diff --git a/core/string_db.h b/core/string_db.h index 28ca812a4..01d1ca403 100644 --- a/core/string_db.h +++ b/core/string_db.h @@ -67,6 +67,7 @@ class StringName { _Data() { cname = NULL; next = prev = NULL; + idx = 0; hash = 0; } }; diff --git a/core/ustring.cpp b/core/ustring.cpp index d74914699..921d20a6f 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -1151,7 +1151,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) { c[chars] = 0; n = p_num; do { - int mod = ABS(n % base); + int mod = n % base; if (mod >= 10) { char a = (capitalize_hex ? 'A' : 'a'); c[--chars] = a + (mod - 10); @@ -1550,8 +1550,7 @@ String::String(const StrRange &p_range) { int String::hex_to_int(bool p_with_prefix) const { - int l = length(); - if (p_with_prefix && l < 3) + if (p_with_prefix && length() < 3) return 0; const CharType *s = ptr(); @@ -1560,17 +1559,13 @@ int String::hex_to_int(bool p_with_prefix) const { if (sign < 0) { s++; - l--; - if (p_with_prefix && l < 2) - return 0; } if (p_with_prefix) { if (s[0] != '0' || s[1] != 'x') return 0; s += 2; - l -= 2; - }; + } int hex = 0; @@ -1596,8 +1591,7 @@ int String::hex_to_int(bool p_with_prefix) const { int64_t String::hex_to_int64(bool p_with_prefix) const { - int l = length(); - if (p_with_prefix && l < 3) + if (p_with_prefix && length() < 3) return 0; const CharType *s = ptr(); @@ -1606,17 +1600,13 @@ int64_t String::hex_to_int64(bool p_with_prefix) const { if (sign < 0) { s++; - l--; - if (p_with_prefix && l < 2) - return 0; } if (p_with_prefix) { if (s[0] != '0' || s[1] != 'x') return 0; s += 2; - l -= 2; - }; + } int64_t hex = 0; @@ -2997,6 +2987,40 @@ String String::strip_escapes() const { return substr(beg, end - beg); } +String String::lstrip(const Vector<CharType> &p_chars) const { + + int len = length(); + int beg; + + for (beg = 0; beg < len; beg++) { + + if (p_chars.find(operator[](beg)) == -1) + break; + } + + if (beg == 0) + return *this; + + return substr(beg, len - beg); +} + +String String::rstrip(const Vector<CharType> &p_chars) const { + + int len = length(); + int end; + + for (end = len - 1; end >= 0; end--) { + + if (p_chars.find(operator[](end)) == -1) + break; + } + + if (end == len - 1) + return *this; + + return substr(0, end + 1); +} + String String::simplify_path() const { String s = *this; @@ -3165,7 +3189,7 @@ String String::word_wrap(int p_chars_per_line) const { return ret; } -String String::percent_encode() const { +String String::http_escape() const { const CharString temp = utf8(); String res; for (int i = 0; i < temp.length(); ++i) { @@ -3189,7 +3213,7 @@ String String::percent_encode() const { return res; } -String String::percent_decode() const { +String String::http_unescape() const { String res; for (int i = 0; i < length(); ++i) { if (ord_at(i) == '%' && i + 2 < length()) { @@ -3448,6 +3472,24 @@ String String::pad_zeros(int p_digits) const { return s; } +String String::trim_prefix(const String &p_prefix) const { + + String s = *this; + if (s.begins_with(p_prefix)) { + return s.substr(p_prefix.length(), s.length() - p_prefix.length()); + } + return s; +} + +String String::trim_suffix(const String &p_suffix) const { + + String s = *this; + if (s.ends_with(p_suffix)) { + return s.substr(0, s.length() - p_suffix.length()); + } + return s; +} + bool String::is_valid_integer() const { int len = length(); @@ -3478,13 +3520,13 @@ bool String::is_valid_hex_number(bool p_with_prefix) const { if (p_with_prefix) { - if (len < 2) + if (len < 3) return false; if (operator[](from) != '0' || operator[](from + 1) != 'x') { return false; - }; + } from += 2; - }; + } for (int i = from; i < len; i++) { @@ -3492,7 +3534,7 @@ bool String::is_valid_hex_number(bool p_with_prefix) const { if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) continue; return false; - }; + } return true; }; @@ -3713,8 +3755,8 @@ String String::get_file() const { String String::get_extension() const { int pos = find_last("."); - if (pos < 0) - return *this; + if (pos < 0 || pos < MAX(find_last("/"), find_last("\\"))) + return ""; return substr(pos + 1, length()); } @@ -3727,10 +3769,72 @@ String String::plus_file(const String &p_file) const { return *this + "/" + p_file; } +String String::percent_encode() const { + + CharString cs = utf8(); + String encoded; + for (int i = 0; i < cs.length(); i++) { + uint8_t c = cs[i]; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '~' || c == '.') { + + char p[2] = { (char)c, 0 }; + encoded += p; + } else { + char p[4] = { '%', 0, 0, 0 }; + static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; + + p[1] = hex[c >> 4]; + p[2] = hex[c & 0xF]; + encoded += p; + } + } + + return encoded; +} +String String::percent_decode() const { + + CharString pe; + + CharString cs = utf8(); + for (int i = 0; i < cs.length(); i++) { + + uint8_t c = cs[i]; + if (c == '%' && i < length() - 2) { + + uint8_t a = LOWERCASE(cs[i + 1]); + uint8_t b = LOWERCASE(cs[i + 2]); + + c = 0; + if (a >= '0' && a <= '9') + c = (a - '0') << 4; + else if (a >= 'a' && a <= 'f') + c = (a - 'a' + 10) << 4; + else + continue; + + uint8_t d = 0; + + if (b >= '0' && b <= '9') + d = (b - '0'); + else if (b >= 'a' && b <= 'f') + d = (b - 'a' + 10); + else + continue; + c += d; + i += 2; + } + pe.push_back(c); + } + + pe.push_back(0); + + return String::utf8(pe.ptr()); +} + String String::get_basename() const { int pos = find_last("."); - if (pos < 0) + if (pos < 0 || pos < MAX(find_last("/"), find_last("\\"))) return *this; return substr(0, pos); diff --git a/core/ustring.h b/core/ustring.h index 8023c9b95..1ed694bb8 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -137,6 +137,8 @@ public: String insert(int p_at_pos, const String &p_string) const; String pad_decimals(int p_digits) const; String pad_zeros(int p_digits) const; + String trim_prefix(const String &p_prefix) const; + String trim_suffix(const String &p_suffix) const; String lpad(int min_length, const String &character = " ") const; String rpad(int min_length, const String &character = " ") const; String sprintf(const Array &values, bool *error) const; @@ -188,6 +190,8 @@ public: String dedent() const; String strip_edges(bool left = true, bool right = true) const; String strip_escapes() const; + String lstrip(const Vector<CharType> &p_chars) const; + String rstrip(const Vector<CharType> &p_chars) const; String get_extension() const; String get_basename() const; String plus_file(const String &p_file) const; @@ -226,14 +230,17 @@ public: String xml_escape(bool p_escape_quotes = false) const; String xml_unescape() const; - String percent_encode() const; - String percent_decode() const; + String http_escape() const; + String http_unescape() const; String c_escape() const; String c_escape_multiline() const; String c_unescape() const; String json_escape() const; String word_wrap(int p_chars_per_line) const; + String percent_encode() const; + String percent_decode() const; + bool is_valid_identifier() const; bool is_valid_integer() const; bool is_valid_float() const; diff --git a/core/variant.cpp b/core/variant.cpp index 5d48c8785..a6df95e31 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -3167,7 +3167,11 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method, if (ce.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { int errorarg = ce.argument; - err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + "."; + if (p_argptrs) { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(p_argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(ce.expected) + "."; + } else { + err_text = "Cannot convert argument " + itos(errorarg + 1) + " from [missing argptr, type unknown] to " + Variant::get_type_name(ce.expected) + "."; + } } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { err_text = "Method expected " + itos(ce.argument) + " arguments, but called with " + itos(p_argcount) + "."; } else if (ce.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { diff --git a/core/variant_call.cpp b/core/variant_call.cpp index c6e093010..1b938e3f4 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -153,9 +153,9 @@ struct _VariantCall { funcdata.func = p_func; funcdata.default_args = p_defaultarg; funcdata._const = p_const; + funcdata.returns = p_has_return; #ifdef DEBUG_ENABLED funcdata.return_type = p_return; - funcdata.returns = p_has_return; #endif if (p_argtype1.name) { @@ -264,6 +264,8 @@ struct _VariantCall { VCALL_LOCALMEM1R(String, right); VCALL_LOCALMEM0R(String, dedent); VCALL_LOCALMEM2R(String, strip_edges); + VCALL_LOCALMEM1R(String, lstrip); + VCALL_LOCALMEM1R(String, rstrip); VCALL_LOCALMEM0R(String, get_extension); VCALL_LOCALMEM0R(String, get_basename); VCALL_LOCALMEM1R(String, plus_file); @@ -296,6 +298,8 @@ struct _VariantCall { VCALL_LOCALMEM0R(String, hex_to_int); VCALL_LOCALMEM1R(String, pad_decimals); VCALL_LOCALMEM1R(String, pad_zeros); + VCALL_LOCALMEM1R(String, trim_prefix); + VCALL_LOCALMEM1R(String, trim_suffix); static void _call_String_to_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) { @@ -1460,6 +1464,8 @@ void register_variant_methods() { ADDFUNC1R(STRING, STRING, String, left, INT, "position", varray()); ADDFUNC1R(STRING, STRING, String, right, INT, "position", varray()); ADDFUNC2R(STRING, STRING, String, strip_edges, BOOL, "left", BOOL, "right", varray(true, true)); + ADDFUNC1R(STRING, STRING, String, lstrip, STRING, "chars", varray()); + ADDFUNC1R(STRING, STRING, String, rstrip, STRING, "chars", varray()); ADDFUNC0R(STRING, STRING, String, get_extension, varray()); ADDFUNC0R(STRING, STRING, String, get_basename, varray()); ADDFUNC1R(STRING, STRING, String, plus_file, STRING, "file", varray()); @@ -1493,6 +1499,8 @@ void register_variant_methods() { ADDFUNC0R(STRING, INT, String, hex_to_int, varray()); ADDFUNC1R(STRING, STRING, String, pad_decimals, INT, "digits", varray()); ADDFUNC1R(STRING, STRING, String, pad_zeros, INT, "digits", varray()); + ADDFUNC1R(STRING, STRING, String, trim_prefix, STRING, "prefix", varray()); + ADDFUNC1R(STRING, STRING, String, trim_suffix, STRING, "suffix", varray()); ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray()); ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray()); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 8ad981ed0..621af2dfb 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -1459,13 +1459,13 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool v->a = p_value._data._int / 255.0; valid = true; } else if (p_index == CoreStringNames::singleton->h) { - v->set_hsv(p_value._data._int, v->get_s(), v->get_v()); + v->set_hsv(p_value._data._int, v->get_s(), v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->s) { - v->set_hsv(v->get_h(), p_value._data._int, v->get_v()); + v->set_hsv(v->get_h(), p_value._data._int, v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->v) { - v->set_hsv(v->get_h(), v->get_v(), p_value._data._int); + v->set_hsv(v->get_h(), v->get_v(), p_value._data._int, v->a); valid = true; } } else if (p_value.type == Variant::REAL) { @@ -1495,13 +1495,13 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool v->a = p_value._data._real / 255.0; valid = true; } else if (p_index == CoreStringNames::singleton->h) { - v->set_hsv(p_value._data._real, v->get_s(), v->get_v()); + v->set_hsv(p_value._data._real, v->get_s(), v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->s) { - v->set_hsv(v->get_h(), p_value._data._real, v->get_v()); + v->set_hsv(v->get_h(), p_value._data._real, v->get_v(), v->a); valid = true; } else if (p_index == CoreStringNames::singleton->v) { - v->set_hsv(v->get_h(), v->get_s(), p_value._data._real); + v->set_hsv(v->get_h(), v->get_s(), p_value._data._real, v->a); valid = true; } } @@ -2117,15 +2117,15 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } else if (*str == "h") { valid = true; - v->set_hsv(p_value, v->get_s(), v->get_v()); + v->set_hsv(p_value, v->get_s(), v->get_v(), v->a); return; } else if (*str == "s") { valid = true; - v->set_hsv(v->get_h(), p_value, v->get_v()); + v->set_hsv(v->get_h(), p_value, v->get_v(), v->a); return; } else if (*str == "v") { valid = true; - v->set_hsv(v->get_h(), v->get_s(), p_value); + v->set_hsv(v->get_h(), v->get_s(), p_value, v->a); return; } else if (*str == "r8") { valid = true; @@ -3728,8 +3728,9 @@ static const char *_op_names[Variant::OP_MAX] = { "*", "/", "- (negation)", + "+ (positive)", "%", - "..", + "+ (concatenation)", "<<", ">>", "&", |
