diff options
138 files changed, 1231 insertions, 1347 deletions
diff --git a/.travis.yml b/.travis.yml index b52e40200f..e16f1ca8a7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,10 @@ language: cpp # OS config, depends on actual 'os' in build matrix dist: xenial -sudo: false + +stages: + - check + - build env: global: @@ -18,6 +21,7 @@ cache: matrix: include: - name: Static checks (clang-format) + stage: check env: STATIC_CHECKS=yes os: linux compiler: gcc @@ -29,6 +33,7 @@ matrix: - clang-format-8 - name: Linux editor (debug, GCC 9, with Mono) + stage: build env: PLATFORM=x11 TOOLS=yes TARGET=debug CACHE_NAME=${PLATFORM}-tools-mono-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="module_mono_enabled=yes mono_glue=no warnings=extra werror=yes" os: linux compiler: gcc-9 @@ -52,6 +57,7 @@ matrix: branch_pattern: coverity_scan - name: Linux export template (release, Clang) + stage: build env: PLATFORM=x11 TOOLS=no TARGET=release CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes" os: linux compiler: clang @@ -61,21 +67,25 @@ matrix: - *linux_deps - name: Android export template (release_debug, Clang) + stage: build env: PLATFORM=android TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-clang EXTRA_ARGS="warnings=extra werror=yes" os: linux compiler: clang - name: macOS editor (debug, Clang) + stage: build env: PLATFORM=osx TOOLS=yes TARGET=debug CACHE_NAME=${PLATFORM}-tools-clang os: osx compiler: clang - name: iOS export template (debug, Clang) + stage: build env: PLATFORM=iphone TOOLS=no TARGET=debug CACHE_NAME=${PLATFORM}-clang os: osx compiler: clang - name: Linux headless editor (release_debug, GCC 9) + stage: build env: PLATFORM=server TOOLS=yes TARGET=release_debug CACHE_NAME=${PLATFORM}-tools-gcc-9 MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" EXTRA_ARGS="warnings=extra werror=yes" os: linux compiler: gcc-9 @@ -88,6 +98,7 @@ matrix: - *linux_deps - name: Linux export template (release_debug, GCC 5, without 3D support) + stage: build env: PLATFORM=x11 TOOLS=no TARGET=release_debug CACHE_NAME=${PLATFORM}-gcc-5 EXTRA_ARGS="disable_3d=yes" os: linux compiler: gcc diff --git a/core/array.cpp b/core/array.cpp index a334af2c04..108d9f7386 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -133,18 +133,12 @@ void Array::erase(const Variant &p_value) { } Variant Array::front() const { - if (_p->array.size() == 0) { - ERR_EXPLAIN("Can't take value from empty array"); - ERR_FAIL_V(Variant()); - } + ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array."); return operator[](0); } Variant Array::back() const { - if (_p->array.size() == 0) { - ERR_EXPLAIN("Can't take value from empty array"); - ERR_FAIL_V(Variant()); - } + ERR_FAIL_COND_V_MSG(_p->array.size() == 0, Variant(), "Can't take value from empty array."); return operator[](_p->array.size() - 1); } diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index b41b84ab1e..56369a3cc6 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -73,10 +73,7 @@ RES _ResourceLoader::load(const String &p_path, const String &p_type_hint, bool Error err = OK; RES ret = ResourceLoader::load(p_path, p_type_hint, p_no_cache, &err); - if (err != OK) { - ERR_EXPLAIN("Error loading resource: '" + p_path + "'"); - ERR_FAIL_V(ret); - } + ERR_FAIL_COND_V_MSG(err != OK, ret, "Error loading resource: '" + p_path + "'."); return ret; } @@ -148,10 +145,7 @@ _ResourceLoader::_ResourceLoader() { } Error _ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) { - if (p_resource.is_null()) { - ERR_EXPLAIN("Can't save empty resource to path: " + String(p_path)) - ERR_FAIL_V(ERR_INVALID_PARAMETER); - } + ERR_FAIL_COND_V_MSG(p_resource.is_null(), ERR_INVALID_PARAMETER, "Can't save empty resource to path: " + String(p_path) + "."); return ResourceSaver::save(p_path, p_resource, p_flags); } @@ -727,22 +721,16 @@ int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; - ERR_EXPLAIN("Invalid second value of: " + itos(second)); - ERR_FAIL_COND_V(second > 59, 0); + ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + "."); - ERR_EXPLAIN("Invalid minute value of: " + itos(minute)); - ERR_FAIL_COND_V(minute > 59, 0); + ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); - ERR_EXPLAIN("Invalid hour value of: " + itos(hour)); - ERR_FAIL_COND_V(hour > 23, 0); + ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); - ERR_EXPLAIN("Invalid month value of: " + itos(month)); - ERR_FAIL_COND_V(month > 12 || month == 0, 0); + 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_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); - + 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; @@ -2621,8 +2609,7 @@ void _Thread::_start_func(void *ud) { } } - ERR_EXPLAIN("Could not call function '" + t->target_method.operator String() + "'' starting thread ID: " + t->get_id() + " Reason: " + reason); - ERR_FAIL(); + ERR_FAIL_MSG("Could not call function '" + t->target_method.operator String() + "'' starting thread ID: " + t->get_id() + " Reason: " + reason + "."); } } @@ -2704,10 +2691,7 @@ _Thread::_Thread() { _Thread::~_Thread() { - if (active) { - ERR_EXPLAIN("Reference to a Thread object object was lost while the thread is still running..."); - } - ERR_FAIL_COND(active); + ERR_FAIL_COND_MSG(active, "Reference to a Thread object object was lost while the thread is still running..."); } ///////////////////////////////////// diff --git a/core/class_db.cpp b/core/class_db.cpp index 49e3f94d8f..3ad59bc309 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -836,10 +836,7 @@ void ClassDB::add_signal(StringName p_class, const MethodInfo &p_signal) { #ifdef DEBUG_METHODS_ENABLED ClassInfo *check = type; while (check) { - if (check->signal_map.has(sname)) { - ERR_EXPLAIN("Type " + String(p_class) + " already has signal: " + String(sname)); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(check->signal_map.has(sname), "Type " + String(p_class) + " already has signal: " + String(sname) + "."); check = check->inherits_ptr; } #endif @@ -924,16 +921,11 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons if (p_setter) { mb_set = get_method(p_class, p_setter); #ifdef DEBUG_METHODS_ENABLED - if (!mb_set) { - ERR_EXPLAIN("Invalid Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name); - ERR_FAIL(); - } else { - int exp_args = 1 + (p_index >= 0 ? 1 : 0); - if (mb_set->get_argument_count() != exp_args) { - ERR_EXPLAIN("Invalid Function for Setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name); - ERR_FAIL(); - } - } + + ERR_FAIL_COND_MSG(!mb_set, "Invalid setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name + "."); + + int exp_args = 1 + (p_index >= 0 ? 1 : 0); + ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, "Invalid function for setter: " + p_class + "::" + p_setter + " for property: " + p_pinfo.name + "."); #endif } @@ -943,25 +935,15 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons mb_get = get_method(p_class, p_getter); #ifdef DEBUG_METHODS_ENABLED - if (!mb_get) { - ERR_EXPLAIN("Invalid Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name); - ERR_FAIL(); - } else { + ERR_FAIL_COND_MSG(!mb_get, "Invalid getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name + "."); - int exp_args = 0 + (p_index >= 0 ? 1 : 0); - if (mb_get->get_argument_count() != exp_args) { - ERR_EXPLAIN("Invalid Function for Getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name); - ERR_FAIL(); - } - } + int exp_args = 0 + (p_index >= 0 ? 1 : 0); + ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, "Invalid function for getter: " + p_class + "::" + p_getter + " for property: " + p_pinfo.name + "."); #endif } #ifdef DEBUG_METHODS_ENABLED - if (type->property_setget.has(p_pinfo.name)) { - ERR_EXPLAIN("Object " + p_class + " already has property: " + p_pinfo.name); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(type->property_setget.has(p_pinfo.name), "Object " + p_class + " already has property: " + p_pinfo.name + "."); #endif OBJTYPE_WLOCK @@ -1240,32 +1222,26 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const c #ifdef DEBUG_ENABLED - if (has_method(instance_type, mdname)) { - ERR_EXPLAIN("Class " + String(instance_type) + " already has a method " + String(mdname)); - ERR_FAIL_V(NULL); - } + ERR_FAIL_COND_V_MSG(has_method(instance_type, mdname), NULL, "Class " + String(instance_type) + " already has a method " + String(mdname) + "."); #endif ClassInfo *type = classes.getptr(instance_type); if (!type) { - ERR_PRINTS("Couldn't bind method '" + mdname + "' for instance: " + instance_type); memdelete(p_bind); - ERR_FAIL_V(NULL); + ERR_FAIL_V_MSG(NULL, "Couldn't bind method '" + mdname + "' for instance: " + instance_type + "."); } if (type->method_map.has(mdname)) { memdelete(p_bind); // overloading not supported - ERR_EXPLAIN("Method already bound: " + instance_type + "::" + mdname); - ERR_FAIL_V(NULL); + ERR_FAIL_V_MSG(NULL, "Method already bound: " + instance_type + "::" + mdname + "."); } #ifdef DEBUG_METHODS_ENABLED if (method_name.args.size() > p_bind->get_argument_count()) { memdelete(p_bind); - ERR_EXPLAIN("Method definition provides more arguments than the method actually has: " + instance_type + "::" + mdname); - ERR_FAIL_V(NULL); + ERR_FAIL_V_MSG(NULL, "Method definition provides more arguments than the method actually has: " + instance_type + "::" + mdname + "."); } p_bind->set_argument_names(method_name.args); diff --git a/core/class_db.h b/core/class_db.h index 3864522be4..092469beb7 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -306,8 +306,7 @@ public: if (type->method_map.has(p_name)) { memdelete(bind); // overloading not supported - ERR_EXPLAIN("Method already bound: " + instance_type + "::" + p_name); - ERR_FAIL_V(NULL); + ERR_FAIL_V_MSG(NULL, "Method already bound: " + instance_type + "::" + p_name + "."); } type->method_map[p_name] = bind; #ifdef DEBUG_METHODS_ENABLED diff --git a/core/color.cpp b/core/color.cpp index 1843532124..a54a3115cc 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -335,36 +335,23 @@ Color Color::html(const String &p_color) { } else if (color.length() == 6) { alpha = false; } else { - ERR_EXPLAIN("Invalid Color Code: " + p_color); - ERR_FAIL_V(Color()); + ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + "."); } int a = 255; if (alpha) { a = _parse_col(color, 0); - if (a < 0) { - ERR_EXPLAIN("Invalid Color Code: " + p_color); - ERR_FAIL_V(Color()); - } + ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + "."); } int from = alpha ? 2 : 0; int r = _parse_col(color, from + 0); - if (r < 0) { - ERR_EXPLAIN("Invalid Color Code: " + p_color); - ERR_FAIL_V(Color()); - } + ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + "."); int g = _parse_col(color, from + 2); - if (g < 0) { - ERR_EXPLAIN("Invalid Color Code: " + p_color); - ERR_FAIL_V(Color()); - } + ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + "."); int b = _parse_col(color, from + 4); - if (b < 0) { - ERR_EXPLAIN("Invalid Color Code: " + p_color); - ERR_FAIL_V(Color()); - } + ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + "."); return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0); } @@ -425,12 +412,8 @@ Color Color::named(const String &p_name) { name = name.to_lower(); const Map<String, Color>::Element *color = _named_colors.find(name); - if (color) { - return color->value(); - } else { - ERR_EXPLAIN("Invalid Color Name: " + p_name); - ERR_FAIL_V(Color()); - } + ERR_FAIL_NULL_V_MSG(color, Color(), "Invalid color name: " + p_name + "."); + return color->value(); } String _to_hex(float p_val) { @@ -523,8 +506,7 @@ Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { // FIXME: Remove once Godot 3.1 has been released float Color::gray() const { - ERR_EXPLAIN("Color.gray() is deprecated and will be removed in a future version. Use Color.get_v() for a better grayscale approximation."); - WARN_DEPRECATED; + WARN_DEPRECATED_MSG("Color.gray() is deprecated and will be removed in a future version. Use Color.get_v() for a better grayscale approximation."); return (r + g + b) / 3.0; } diff --git a/core/engine.cpp b/core/engine.cpp index 0dd0459403..937439faaf 100644 --- a/core/engine.cpp +++ b/core/engine.cpp @@ -197,10 +197,7 @@ void Engine::add_singleton(const Singleton &p_singleton) { Object *Engine::get_singleton_object(const String &p_name) const { const Map<StringName, Object *>::Element *E = singleton_ptrs.find(p_name); - if (!E) { - ERR_EXPLAIN("Failed to retrieve non-existent singleton '" + p_name + "'"); - ERR_FAIL_V(NULL); - } + ERR_FAIL_COND_V_MSG(!E, NULL, "Failed to retrieve non-existent singleton '" + p_name + "'."); return E->get(); }; diff --git a/core/hash_map.h b/core/hash_map.h index 1513d7a65b..81ddc376d0 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -151,11 +151,7 @@ private: return; Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power)); - if (!new_hash_table) { - - ERR_PRINT("Out of Memory"); - return; - } + ERR_FAIL_COND_MSG(!new_hash_table, "Out of memory."); for (int i = 0; i < (1 << new_hash_table_power); i++) { @@ -208,10 +204,7 @@ private: /* if element doesn't exist, create it */ Element *e = memnew(Element); - if (!e) { - ERR_EXPLAIN("Out of memory"); - ERR_FAIL_V(NULL); - } + ERR_FAIL_COND_V_MSG(!e, NULL, "Out of memory."); uint32_t hash = Hasher::hash(p_key); uint32_t index = hash & ((1 << hash_table_power) - 1); e->next = hash_table[index]; @@ -498,10 +491,7 @@ public: } else { /* get the next key */ const Element *e = get_element(*p_key); - if (!e) { - ERR_EXPLAIN("Invalid key supplied") - ERR_FAIL_V(NULL); - } + ERR_FAIL_COND_V_MSG(!e, NULL, "Invalid key supplied."); if (e->next) { /* if there is a "next" in the list, return that */ return &e->next->pair.key; diff --git a/core/image.cpp b/core/image.cpp index 6211c06ebe..d8d667dbd5 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -423,8 +423,7 @@ void Image::convert(Format p_new_format) { if (format > FORMAT_RGBE9995 || p_new_format > FORMAT_RGBE9995) { - ERR_EXPLAIN("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead."); - ERR_FAIL(); + ERR_FAIL_MSG("Cannot convert to <-> from compressed formats. Use compress() and decompress() instead."); } else if (format > FORMAT_RGBA8 || p_new_format > FORMAT_RGBA8) { @@ -864,10 +863,7 @@ bool Image::is_size_po2() const { void Image::resize_to_po2(bool p_square) { - if (!_can_modify(format)) { - ERR_EXPLAIN("Cannot resize in indexed, compressed or custom image formats."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in indexed, compressed or custom image formats."); int w = next_power_of_2(width); int h = next_power_of_2(height); @@ -883,15 +879,9 @@ void Image::resize_to_po2(bool p_square) { void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { - if (data.size() == 0) { - ERR_EXPLAIN("Cannot resize image before creating it, use create() or create_from_data() first."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(data.size() == 0, "Cannot resize image before creating it, use create() or create_from_data() first."); - if (!_can_modify(format)) { - ERR_EXPLAIN("Cannot resize in indexed, compressed or custom image formats."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot resize in indexed, compressed or custom image formats."); bool mipmap_aware = p_interpolation == INTERPOLATE_TRILINEAR /* || p_interpolation == INTERPOLATE_TRICUBIC */; @@ -1104,10 +1094,8 @@ void Image::resize(int p_width, int p_height, Interpolation p_interpolation) { void Image::crop_from_point(int p_x, int p_y, int p_width, int p_height) { - if (!_can_modify(format)) { - ERR_EXPLAIN("Cannot crop in indexed, compressed or custom image formats."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot crop in indexed, compressed or custom image formats."); + ERR_FAIL_COND(p_x < 0); ERR_FAIL_COND(p_y < 0); ERR_FAIL_COND(p_width <= 0); @@ -1161,10 +1149,7 @@ void Image::crop(int p_width, int p_height) { void Image::flip_y() { - if (!_can_modify(format)) { - ERR_EXPLAIN("Cannot flip_y in indexed, compressed or custom image formats."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_y in indexed, compressed or custom image formats."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1197,10 +1182,7 @@ void Image::flip_y() { void Image::flip_x() { - if (!_can_modify(format)) { - ERR_EXPLAIN("Cannot flip_x in indexed, compressed or custom image formats."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot flip_x in indexed, compressed or custom image formats."); bool used_mipmaps = has_mipmaps(); if (used_mipmaps) { @@ -1459,15 +1441,9 @@ void Image::normalize() { Error Image::generate_mipmaps(bool p_renormalize) { - if (!_can_modify(format)) { - ERR_EXPLAIN("Cannot generate mipmaps in indexed, compressed or custom image formats."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(!_can_modify(format), ERR_UNAVAILABLE, "Cannot generate mipmaps in indexed, compressed or custom image formats."); - if (width == 0 || height == 0) { - ERR_EXPLAIN("Cannot generate mipmaps with width or height equal to 0."); - ERR_FAIL_V(ERR_UNCONFIGURED); - } + ERR_FAIL_COND_V_MSG(width == 0 || height == 0, ERR_UNCONFIGURED, "Cannot generate mipmaps with width or height equal to 0."); int mmcount; @@ -1618,10 +1594,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma int mm; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); - if (size != p_data.size()) { - ERR_EXPLAIN("Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes."); - ERR_FAIL_COND(p_data.size() != size); - } + ERR_FAIL_COND_MSG(p_data.size() != size, "Expected data size of " + itos(size) + " bytes in Image::create(), got instead " + itos(p_data.size()) + " bytes."); height = p_height; width = p_width; @@ -2411,10 +2384,7 @@ Color Image::get_pixel(int p_x, int p_y) const { uint8_t *ptr = write_lock.ptr(); #ifdef DEBUG_ENABLED - if (!ptr) { - ERR_EXPLAIN("Image must be locked with 'lock()' before using get_pixel()"); - ERR_FAIL_V(Color()); - } + ERR_FAIL_COND_V_MSG(!ptr, Color(), "Image must be locked with 'lock()' before using get_pixel()."); ERR_FAIL_INDEX_V(p_x, width, Color()); ERR_FAIL_INDEX_V(p_y, height, Color()); @@ -2530,8 +2500,7 @@ Color Image::get_pixel(int p_x, int p_y) const { return Color::from_rgbe9995(((uint32_t *)ptr)[ofs]); } default: { - ERR_EXPLAIN("Can't get_pixel() on compressed image, sorry."); - ERR_FAIL_V(Color()); + ERR_FAIL_V_MSG(Color(), "Can't get_pixel() on compressed image, sorry."); } } } @@ -2544,10 +2513,7 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { uint8_t *ptr = write_lock.ptr(); #ifdef DEBUG_ENABLED - if (!ptr) { - ERR_EXPLAIN("Image must be locked with 'lock()' before using set_pixel()"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!ptr, "Image must be locked with 'lock()' before using set_pixel()."); ERR_FAIL_INDEX(p_x, width); ERR_FAIL_INDEX(p_y, height); @@ -2659,8 +2625,7 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { } break; default: { - ERR_EXPLAIN("Can't set_pixel() on compressed image, sorry."); - ERR_FAIL(); + ERR_FAIL_MSG("Can't set_pixel() on compressed image, sorry."); } } } diff --git a/core/input_map.cpp b/core/input_map.cpp index 165999f081..2a8ac435fe 100644 --- a/core/input_map.cpp +++ b/core/input_map.cpp @@ -192,10 +192,7 @@ bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName 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_V(false); - } + ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action: " + String(p_action) + "."); Ref<InputEventAction> input_event_action = p_event; if (input_event_action.is_valid()) { diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp index f7fb72c089..70bb816acd 100644 --- a/core/io/config_file.cpp +++ b/core/io/config_file.cpp @@ -86,10 +86,7 @@ void ConfigFile::set_value(const String &p_section, const String &p_key, const V Variant ConfigFile::get_value(const String &p_section, const String &p_key, Variant p_default) const { if (!values.has(p_section) || !values[p_section].has(p_key)) { - if (p_default.get_type() == Variant::NIL) { - ERR_EXPLAIN("Couldn't find the given section/key and no default was given"); - ERR_FAIL_V(p_default); - } + ERR_FAIL_COND_V_MSG(p_default.get_type() == Variant::NIL, p_default, "Couldn't find the given section/key and no default was given."); return p_default; } return values[p_section][p_key]; @@ -271,7 +268,7 @@ Error ConfigFile::_internal_load(const String &p_path, FileAccess *f) { memdelete(f); return OK; } else if (err != OK) { - ERR_PRINTS("ConfgFile::load - " + p_path + ":" + itos(lines) + " error: " + error_text); + ERR_PRINTS("ConfgFile::load - " + p_path + ":" + itos(lines) + " error: " + error_text + "."); memdelete(f); return err; } diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp index 15523a49a9..f72ad61da6 100644 --- a/core/io/file_access_buffered.cpp +++ b/core/io/file_access_buffered.cpp @@ -87,10 +87,8 @@ bool FileAccessBuffered::eof_reached() const { } uint8_t FileAccessBuffered::get_8() const { - if (!file.open) { - ERR_EXPLAIN("Can't get data, when file is not opened."); - ERR_FAIL_V(0); - } + + ERR_FAIL_COND_V_MSG(!file.open, 0, "Can't get data, when file is not opened."); uint8_t byte = 0; if (cache_data_left() >= 1) { @@ -104,10 +102,8 @@ uint8_t FileAccessBuffered::get_8() const { } int FileAccessBuffered::get_buffer(uint8_t *p_dest, int p_length) const { - if (!file.open) { - ERR_EXPLAIN("Can't get buffer, when file is not opened."); - ERR_FAIL_V(-1); - } + + ERR_FAIL_COND_V_MSG(!file.open, -1, "Can't get buffer, when file is not opened."); if (p_length > cache_size) { diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index 6e806e7b3f..c8cee04208 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -40,10 +40,7 @@ class FileAccessBufferedFA : public FileAccessBuffered { int read_data_block(int p_offset, int p_size, uint8_t *p_dest = 0) const { - if (!f.is_open()) { - ERR_EXPLAIN("Can't read data block, when file is not opened."); - ERR_FAIL_V(-1); - } + ERR_FAIL_COND_V_MSG(!f.is_open(), -1, "Can't read data block when file is not opened."); ((T *)&f)->seek(p_offset); diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index ccee6aeb15..1452c61d1a 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -94,8 +94,7 @@ Error FileAccessEncrypted::open_and_parse(FileAccess *p_base, const Vector<uint8 unsigned char hash[16]; ERR_FAIL_COND_V(CryptoCore::md5(data.ptr(), data.size(), hash) != OK, ERR_BUG); - ERR_EXPLAIN("The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid."); - ERR_FAIL_COND_V(String::md5(hash) != String::md5(md5d), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V_MSG(String::md5(hash) != String::md5(md5d), ERR_FILE_CORRUPT, "The MD5 sum of the decrypted file does not match the expected value. It could be that the file is corrupt, or that the provided decryption key is invalid."); file = p_base; } @@ -298,7 +297,7 @@ uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) { } Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { - ERR_PRINT("Setting UNIX permissions on encrypted files is not implemented yet"); + ERR_PRINT("Setting UNIX permissions on encrypted files is not implemented yet."); return ERR_UNAVAILABLE; } diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index ca66b34e17..d49d36c2b9 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -90,7 +90,7 @@ void PackedData::add_path(const String &pkg_path, const String &path, uint64_t o } } String filename = path.get_file(); - // Don't add as a file if the path points to a directoryy + // Don't add as a file if the path points to a directory if (!filename.empty()) { cd->files.insert(filename); } @@ -171,10 +171,8 @@ bool PackedSourcePCK::try_open_pack(const String &p_path) { uint32_t ver_minor = f->get_32(); f->get_32(); // ver_rev - ERR_EXPLAIN("Pack version unsupported: " + itos(version)); - ERR_FAIL_COND_V(version != PACK_VERSION, false); - ERR_EXPLAIN("Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor)); - ERR_FAIL_COND_V(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false); + ERR_FAIL_COND_V_MSG(version != PACK_VERSION, false, "Pack version unsupported: " + itos(version) + "."); + ERR_FAIL_COND_V_MSG(ver_major > VERSION_MAJOR || (ver_major == VERSION_MAJOR && ver_minor > VERSION_MINOR), false, "Pack created with a newer version of the engine: " + itos(ver_major) + "." + itos(ver_minor) + "."); for (int i = 0; i < 16; i++) { //reserved @@ -322,10 +320,9 @@ bool FileAccessPack::file_exists(const String &p_name) { FileAccessPack::FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file) : pf(p_file), f(FileAccess::open(pf.pack, FileAccess::READ)) { - if (!f) { - ERR_EXPLAIN("Can't open pack-referenced file: " + String(pf.pack)); - ERR_FAIL_COND(!f); - } + + ERR_FAIL_COND_MSG(!f, "Can't open pack-referenced file: " + String(pf.pack) + "."); + f->seek(pf.offset); pos = 0; eof = false; @@ -463,11 +460,15 @@ String DirAccessPack::get_current_dir() { bool DirAccessPack::file_exists(String p_file) { + p_file = fix_path(p_file); + return current->files.has(p_file); } bool DirAccessPack::dir_exists(String p_dir) { + p_dir = fix_path(p_dir); + return current->subdirs.has(p_dir); } diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp index 9305afac5f..df4be9b9fd 100644 --- a/core/io/ip_address.cpp +++ b/core/io/ip_address.cpp @@ -81,8 +81,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) { } else if (c == ':') { break; } else { - ERR_EXPLAIN("Invalid character in ipv6 address: " + p_string); - ERR_FAIL(); + ERR_FAIL_MSG("Invalid character in IPv6 address: " + p_string + "."); }; ret = ret << 4; ret += n; @@ -126,9 +125,7 @@ void IP_Address::_parse_ipv6(const String &p_string) { ++parts_count; }; } else { - - ERR_EXPLAIN("Invalid character in IPv6 address: " + p_string); - ERR_FAIL(); + ERR_FAIL_MSG("Invalid character in IPv6 address: " + p_string + "."); }; }; @@ -166,10 +163,7 @@ void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret }; int slices = ip.get_slice_count("."); - if (slices != 4) { - ERR_EXPLAIN("Invalid IP Address String: " + ip); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(slices != 4, "Invalid IP address string: " + ip + "."); for (int i = 0; i < 4; i++) { p_ret[i] = ip.get_slicec('.', i).to_int(); } @@ -229,7 +223,7 @@ IP_Address::IP_Address(const String &p_string) { valid = true; } else { - ERR_PRINT("Invalid IP address"); + ERR_PRINT("Invalid IP address."); } } diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index dc5581ea01..b386feb14c 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -377,11 +377,6 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } break; - /*case Variant::RESOURCE: { - - ERR_EXPLAIN("Can't marshallize resources"); - ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go - } break;*/ case Variant::_RID: { r_variant = RID(); @@ -1066,11 +1061,6 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 4 * 4; } break; - /*case Variant::RESOURCE: { - - ERR_EXPLAIN("Can't marshallize resources"); - ERR_FAIL_V(ERR_INVALID_DATA); //no, i'm sorry, no go - } break;*/ case Variant::_RID: { } break; diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index 33dc4dbde4..d20133642b 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -146,8 +146,7 @@ void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_pee network_peer = p_peer; - ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected."); - ERR_FAIL_COND(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED); + ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Supplied NetworkedNetworkPeer must be connecting or connected."); if (network_peer.is_valid()) { network_peer->connect("peer_connected", this, "_add_peer"); @@ -164,10 +163,8 @@ Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const { void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { - ERR_EXPLAIN("Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it"); - ERR_FAIL_COND(root_node == NULL); - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_packet_len < 1); + ERR_FAIL_COND_MSG(root_node == NULL, "Multiplayer root node was not initialized. If you are using custom multiplayer, remember to set the root node via MultiplayerAPI.set_root_node before using it."); + ERR_FAIL_COND_MSG(p_packet_len < 1, "Invalid packet received. Size too small."); uint8_t packet_type = p_packet[0]; @@ -186,13 +183,11 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ case NETWORK_COMMAND_REMOTE_CALL: case NETWORK_COMMAND_REMOTE_SET: { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_packet_len < 6); + ERR_FAIL_COND_MSG(p_packet_len < 6, "Invalid packet received. Size too small."); Node *node = _process_get_node(p_from, p_packet, p_packet_len); - ERR_EXPLAIN("Invalid packet received. Requested node was not found."); - ERR_FAIL_COND(node == NULL); + ERR_FAIL_COND_MSG(node == NULL, "Invalid packet received. Requested node was not found."); // Detect cstring end. int len_end = 5; @@ -202,8 +197,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } } - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(len_end >= p_packet_len); + ERR_FAIL_COND_MSG(len_end >= p_packet_len, "Invalid packet received. Size too small."); StringName name = String::utf8((const char *)&p_packet[5]); @@ -235,8 +229,7 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int int ofs = target & 0x7FFFFFFF; - ERR_EXPLAIN("Invalid packet received. Size smaller than declared."); - ERR_FAIL_COND_V(ofs >= p_packet_len, NULL); + ERR_FAIL_COND_V_MSG(ofs >= p_packet_len, NULL, "Invalid packet received. Size smaller than declared."); String paths; paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); @@ -246,33 +239,30 @@ Node *MultiplayerAPI::_process_get_node(int p_from, const uint8_t *p_packet, int node = root_node->get_node(np); if (!node) - ERR_PRINTS("Failed to get path from RPC: " + String(np)); + ERR_PRINTS("Failed to get path from RPC: " + String(np) + "."); } else { // Use cached path. int id = target; Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from); - ERR_EXPLAIN("Invalid packet received. Requests invalid peer cache."); - ERR_FAIL_COND_V(!E, NULL); + ERR_FAIL_COND_V_MSG(!E, NULL, "Invalid packet received. Requests invalid peer cache."); Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id); - ERR_EXPLAIN("Invalid packet received. Unabled to find requested cached node."); - ERR_FAIL_COND_V(!F, NULL); + ERR_FAIL_COND_V_MSG(!F, NULL, "Invalid packet received. Unabled to find requested cached node."); PathGetCache::NodeInfo *ni = &F->get(); // Do proper caching later. node = root_node->get_node(ni->path); if (!node) - ERR_PRINTS("Failed to get cached path from RPC: " + String(ni->path)); + ERR_PRINTS("Failed to get cached path from RPC: " + String(ni->path) + "."); } return node; } void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_offset >= p_packet_len); + 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. RPCMode rpc_mode = RPC_MODE_DISABLED; @@ -284,8 +274,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ } bool can_call = _can_call_mode(p_node, rpc_mode, p_from); - ERR_EXPLAIN("RPC '" + String(p_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()) + "."); - ERR_FAIL_COND(!can_call); + ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(p_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()) + "."); int argc = p_packet[p_offset]; Vector<Variant> args; @@ -297,13 +286,11 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ for (int i = 0; i < argc; i++) { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_offset >= p_packet_len); + ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); int vlen; Error err = decode_variant(args.write[i], &p_packet[p_offset], p_packet_len - p_offset, &vlen, allow_object_decoding || network_peer->is_object_decoding_allowed()); - ERR_EXPLAIN("Invalid packet received. Unable to decode RPC argument."); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RPC argument."); argp.write[i] = &args[i]; p_offset += vlen; @@ -321,8 +308,7 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const StringName &p_name, int p_ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_offset >= p_packet_len); + 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. RPCMode rset_mode = RPC_MODE_DISABLED; @@ -334,28 +320,25 @@ void MultiplayerAPI::_process_rset(Node *p_node, const StringName &p_name, int p } bool can_call = _can_call_mode(p_node, rset_mode, p_from); - ERR_EXPLAIN("RSET '" + String(p_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()) + "."); - ERR_FAIL_COND(!can_call); + ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(p_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()) + "."); Variant value; Error err = decode_variant(value, &p_packet[p_offset], p_packet_len - p_offset, NULL, allow_object_decoding || network_peer->is_object_decoding_allowed()); - ERR_EXPLAIN("Invalid packet received. Unable to decode RSET value."); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value."); bool valid; p_node->set(p_name, value, &valid); if (!valid) { - String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class(); + String error = "Error setting remote property '" + String(p_name) + "', not found in object of type " + p_node->get_class() + "."; ERR_PRINTS(error); } } void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_packet_len < 5); + ERR_FAIL_COND_MSG(p_packet_len < 5, "Invalid packet received. Size too small."); int id = decode_uint32(&p_packet[1]); String paths; @@ -390,8 +373,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len) { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_packet_len < 2); + ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small."); String paths; paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1); @@ -399,12 +381,10 @@ void MultiplayerAPI::_process_confirm_path(int p_from, const uint8_t *p_packet, NodePath path = paths; PathSentCache *psc = path_send_cache.getptr(path); - ERR_EXPLAIN("Invalid packet received. Tries to confirm a path which was not found in cache."); - ERR_FAIL_COND(!psc); + ERR_FAIL_COND_MSG(!psc, "Invalid packet received. Tries to confirm a path which was not found in cache."); Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from); - ERR_EXPLAIN("Invalid packet received. Source peer was not found in cache for the given path."); - ERR_FAIL_COND(!E); + ERR_FAIL_COND_MSG(!E, "Invalid packet received. Source peer was not found in cache for the given path."); E->get() = true; } @@ -460,39 +440,22 @@ bool MultiplayerAPI::_send_confirm_path(NodePath p_path, PathSentCache *psc, int 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) { - if (network_peer.is_null()) { - ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree."); - if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { - ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); - ERR_FAIL(); - } + 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."); - if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { - ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); - if (p_argcount > 255) { - ERR_EXPLAIN("Too many arguments >255."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255."); if (p_to != 0 && !connected_peers.has(ABS(p_to))) { - if (p_to == network_peer->get_unique_id()) { - ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id())); - } else { - ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); - } + ERR_FAIL_COND_MSG(p_to == network_peer->get_unique_id(), "Attempt to remote call/set yourself! unique ID: " + itos(network_peer->get_unique_id()) + "."); - ERR_FAIL(); + ERR_FAIL_MSG("Attempt to remote call unexisting ID: " + itos(p_to) + "."); } NodePath from_path = (root_node->get_path()).rel_path_to(p_from->get_path()); - ERR_EXPLAIN("Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); - ERR_FAIL_COND(from_path.is_empty()); + ERR_FAIL_COND_MSG(from_path.is_empty(), "Unable to send RPC. Relative path is empty. THIS IS LIKELY A BUG IN THE ENGINE!"); // See if the path is cached. PathSentCache *psc = path_send_cache.getptr(from_path); @@ -530,8 +493,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p if (p_set) { // Set argument. Error err = encode_variant(*p_arg[0], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); - ERR_EXPLAIN("Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); MAKE_ROOM(ofs + len); encode_variant(*p_arg[0], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; @@ -543,8 +505,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p ofs += 1; for (int i = 0; i < p_argcount; i++) { Error err = encode_variant(*p_arg[i], NULL, len, allow_object_decoding || network_peer->is_object_decoding_allowed()); - ERR_EXPLAIN("Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); MAKE_ROOM(ofs + len); encode_variant(*p_arg[i], &(packet_cache.write[ofs]), len, allow_object_decoding || network_peer->is_object_decoding_allowed()); ofs += len; @@ -626,12 +587,9 @@ void MultiplayerAPI::_server_disconnected() { void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { - ERR_EXPLAIN("Trying to call an RPC while no network peer is active."); - ERR_FAIL_COND(!network_peer.is_valid()); - ERR_EXPLAIN("Trying to call an RPC on a node which is not inside SceneTree."); - ERR_FAIL_COND(!p_node->is_inside_tree()); - ERR_EXPLAIN("Trying to call an RPC via a network peer which is not connected."); - ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED); + ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active."); + ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); int node_id = network_peer->get_unique_id(); bool skip_rpc = node_id == p_peer_id; @@ -668,7 +626,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const rpc_sender_id = temp_id; if (ce.error != Variant::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); - error = "rpc() aborted in local call: - " + error; + error = "rpc() aborted in local call: - " + error + "."; ERR_PRINTS(error); return; } @@ -683,24 +641,20 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const rpc_sender_id = temp_id; if (ce.error != Variant::CallError::CALL_OK) { String error = Variant::get_call_error_text(p_node, p_method, p_arg, p_argcount, ce); - error = "rpc() aborted in script local call: - " + error; + error = "rpc() aborted in script local call: - " + error + "."; ERR_PRINTS(error); return; } } - ERR_EXPLAIN("RPC '" + p_method + "' on yourself is not allowed by selected mode"); - ERR_FAIL_COND(skip_rpc && !(call_local_native || call_local_script)); + 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_EXPLAIN("Trying to RSET while no network peer is active."); - ERR_FAIL_COND(!network_peer.is_valid()); - ERR_EXPLAIN("Trying to RSET on a node which is not inside SceneTree."); - ERR_FAIL_COND(!p_node->is_inside_tree()); - ERR_EXPLAIN("Trying to send an RSET via a network peer which is not connected."); - ERR_FAIL_COND(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED); + 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(); @@ -724,7 +678,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const rpc_sender_id = temp_id; if (!valid) { - String error = "rset() aborted in local set, property not found: - " + String(p_property); + String error = "rset() aborted in local set, property not found: - " + String(p_property) + "."; ERR_PRINTS(error); return; } @@ -742,7 +696,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const rpc_sender_id = temp_id; if (!valid) { - String error = "rset() aborted in local script set, property not found: - " + String(p_property); + String error = "rset() aborted in local script set, property not found: - " + String(p_property) + "."; ERR_PRINTS(error); return; } @@ -751,8 +705,7 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const } if (skip_rset) { - ERR_EXPLAIN("RSET for '" + p_property + "' on yourself is not allowed by selected mode"); - ERR_FAIL_COND(!set_local); + ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode."); return; } @@ -763,12 +716,9 @@ void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { - ERR_EXPLAIN("Trying to send an empty raw packet."); - ERR_FAIL_COND_V(p_data.size() < 1, ERR_INVALID_DATA); - ERR_EXPLAIN("Trying to send a raw packet while no network peer is active."); - ERR_FAIL_COND_V(!network_peer.is_valid(), ERR_UNCONFIGURED); - ERR_EXPLAIN("Trying to send a raw packet via a network peer which is not connected."); - ERR_FAIL_COND_V(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED); + 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."); + ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected."); MAKE_ROOM(p_data.size() + 1); PoolVector<uint8_t>::Read r = p_data.read(); @@ -783,8 +733,7 @@ Error MultiplayerAPI::send_bytes(PoolVector<uint8_t> p_data, int p_to, Networked void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_packet_len) { - ERR_EXPLAIN("Invalid packet received. Size too small."); - ERR_FAIL_COND(p_packet_len < 2); + ERR_FAIL_COND_MSG(p_packet_len < 2, "Invalid packet received. Size too small."); PoolVector<uint8_t> out; int len = p_packet_len - 1; @@ -798,37 +747,32 @@ void MultiplayerAPI::_process_raw(int p_from, const uint8_t *p_packet, int p_pac int MultiplayerAPI::get_network_unique_id() const { - ERR_EXPLAIN("No network peer is assigned. Unable to get unique network ID."); - ERR_FAIL_COND_V(!network_peer.is_valid(), 0); + ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), 0, "No network peer is assigned. Unable to get unique network ID."); return network_peer->get_unique_id(); } bool MultiplayerAPI::is_network_server() const { // XXX Maybe fail silently? Maybe should actually return true to make development of both local and online multiplayer easier? - ERR_EXPLAIN("No network peer is assigned. I can't be a server."); - ERR_FAIL_COND_V(!network_peer.is_valid(), false); + ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), false, "No network peer is assigned. I can't be a server."); return network_peer->is_server(); } void MultiplayerAPI::set_refuse_new_network_connections(bool p_refuse) { - ERR_EXPLAIN("No network peer is assigned. Unable to set 'refuse_new_connections'."); - ERR_FAIL_COND(!network_peer.is_valid()); + ERR_FAIL_COND_MSG(!network_peer.is_valid(), "No network peer is assigned. Unable to set 'refuse_new_connections'."); network_peer->set_refuse_new_connections(p_refuse); } bool MultiplayerAPI::is_refusing_new_network_connections() const { - ERR_EXPLAIN("No network peer is assigned. Unable to get 'refuse_new_connections'."); - ERR_FAIL_COND_V(!network_peer.is_valid(), false); + ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), false, "No network peer is assigned. Unable to get 'refuse_new_connections'."); return network_peer->is_refusing_new_connections(); } Vector<int> MultiplayerAPI::get_network_connected_peers() const { - ERR_EXPLAIN("No network peer is assigned. Assume no peers are connected."); - ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>()); + ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), Vector<int>(), "No network peer is assigned. Assume no peers are connected."); Vector<int> ret; for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) { diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 1e4ea715b3..1c792c43d1 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -280,8 +280,7 @@ Ref<StreamPeer> PacketPeerStream::get_stream_peer() const { void PacketPeerStream::set_input_buffer_max_size(int p_max_size) { //warning may lose packets - ERR_EXPLAIN("Buffer in use, resizing would cause loss of data"); - ERR_FAIL_COND(ring_buffer.data_left()); + ERR_FAIL_COND_MSG(ring_buffer.data_left(), "Buffer in use, resizing would cause loss of data."); ring_buffer.resize(nearest_shift(p_max_size + 4)); input_buffer.resize(next_power_of_2(p_max_size + 4)); } diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index c16d89d695..1c89bc6268 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -64,10 +64,7 @@ Error PCKPacker::pck_start(const String &p_file, int p_alignment) { file = FileAccess::open(p_file, FileAccess::WRITE); - if (!file) { - ERR_EXPLAIN("Can't open file to write: " + String(p_file)); - ERR_FAIL_V(ERR_CANT_CREATE); - } + ERR_FAIL_COND_V_MSG(!file, ERR_CANT_CREATE, "Can't open file to write: " + String(p_file) + "."); alignment = p_alignment; diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 146480e5a2..de10fe1376 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -490,8 +490,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { #endif } else { - ERR_EXPLAIN("Vector2 size is NOT 8!"); - ERR_FAIL_V(ERR_UNAVAILABLE); + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector2 size is NOT 8!"); } w.release(); r_v = array; @@ -518,8 +517,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { #endif } else { - ERR_EXPLAIN("Vector3 size is NOT 12!"); - ERR_FAIL_V(ERR_UNAVAILABLE); + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Vector3 size is NOT 12!"); } w.release(); r_v = array; @@ -546,8 +544,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { #endif } else { - ERR_EXPLAIN("Color size is NOT 16!"); - ERR_FAIL_V(ERR_UNAVAILABLE); + ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Color size is NOT 16!"); } w.release(); r_v = array; @@ -571,7 +568,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant &r_v) { const uint32_t current_version = 0; if (format_version > current_version) { - ERR_PRINT("Format version for encoded binary image is too new"); + ERR_PRINT("Format version for encoded binary image is too new."); return ERR_PARSE_ERROR; } @@ -655,8 +652,7 @@ Error ResourceInteractiveLoaderBinary::poll() { } else { error = ERR_FILE_MISSING_DEPENDENCIES; - ERR_EXPLAIN("Can't load dependency: " + path); - ERR_FAIL_V(error); + ERR_FAIL_V_MSG(error, "Can't load dependency: " + path + "."); } } else { @@ -711,16 +707,15 @@ Error ResourceInteractiveLoaderBinary::poll() { Object *obj = ClassDB::instance(t); if (!obj) { error = ERR_FILE_CORRUPT; - ERR_EXPLAIN(local_path + ":Resource of unrecognized type in file: " + t); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + "."); } Resource *r = Object::cast_to<Resource>(obj); if (!r) { + String obj_class = obj->get_class(); error = ERR_FILE_CORRUPT; - ERR_EXPLAIN(local_path + ":Resource type in resource field not a resource, type is: " + obj->get_class()); memdelete(obj); //bye - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource type in resource field not a resource, type is: " + obj_class + "."); } RES res = RES(r); @@ -850,8 +845,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { //not normal error = ERR_FILE_UNRECOGNIZED; - ERR_EXPLAIN("Unrecognized binary resource file: " + local_path); - ERR_FAIL(); + ERR_FAIL_MSG("Unrecognized binary resource file: " + local_path + "."); } bool big_endian = f->get_32(); @@ -877,8 +871,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { f->close(); - ERR_EXPLAIN("File Format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path); - ERR_FAIL(); + ERR_FAIL_MSG("File format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path + "."); } type = get_unicode_string(); @@ -926,8 +919,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { if (f->eof_reached()) { error = ERR_FILE_CORRUPT; - ERR_EXPLAIN("Premature End Of File: " + local_path); - ERR_FAIL(); + ERR_FAIL_MSG("Premature end of file (EOF): " + local_path + "."); } } @@ -1084,8 +1076,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons //error=ERR_FILE_UNRECOGNIZED; memdelete(f); - ERR_EXPLAIN("Unrecognized binary resource file: " + local_path); - ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unrecognized binary resource file: " + local_path + "."); } else { fw = FileAccess::open(p_path + ".depren", FileAccess::WRITE); if (!fw) { @@ -1122,7 +1113,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons memdelete(da); //use the old approach - WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: " + p_path).utf8().get_data()); + WARN_PRINTS("This file is old, so it can't refactor dependencies, opening and resaving: " + p_path + "."); Error err; f = FileAccess::open(p_path, FileAccess::READ, &err); @@ -1153,8 +1144,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons memdelete(f); memdelete(fw); - ERR_EXPLAIN("File Format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path); - ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "File format '" + itos(FORMAT_VERSION) + "." + itos(ver_major) + "." + itos(ver_minor) + "' is too new! Please upgrade to a new engine version: " + local_path + "."); } // Since we're not actually converting the file contents, leave the version @@ -1477,7 +1467,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia case Variant::_RID: { f->store_32(VARIANT_RID); - WARN_PRINT("Can't save RIDs"); + WARN_PRINT("Can't save RIDs."); RID val = p_property; f->store_32(val.get_id()); } break; @@ -1497,8 +1487,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia if (!resource_set.has(res)) { f->store_32(OBJECT_EMPTY); - ERR_EXPLAIN("Resource was not pre cached for the resource section, most likely due to circular refedence."); - ERR_FAIL(); + ERR_FAIL_MSG("Resource was not pre cached for the resource section, most likely due to circular reference."); } f->store_32(OBJECT_INTERNAL_RESOURCE); @@ -1629,8 +1618,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia } break; default: { - ERR_EXPLAIN("Invalid variant"); - ERR_FAIL(); + ERR_FAIL_MSG("Invalid variant."); } } } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 35af58ad07..9e954890bc 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -275,12 +275,9 @@ RES ResourceLoader::_load(const String &p_path, const String &p_original_path, c return res; } - if (found) { - ERR_EXPLAIN("Failed loading resource: " + p_path); - } else { - ERR_EXPLAIN("No loader found for resource: " + p_path); - } - ERR_FAIL_V(RES()); + ERR_FAIL_COND_V_MSG(found, RES(), "Failed loading resource: " + p_path + "."); + + ERR_FAIL_V_MSG(RES(), "No loader found for resource: " + p_path + "."); } bool ResourceLoader::_add_to_loading_map(const String &p_path) { @@ -355,10 +352,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p { bool success = _add_to_loading_map(local_path); - if (!success) { - ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); - ERR_FAIL_V(RES()); - } + ERR_FAIL_COND_V_MSG(!success, RES(), "Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); } //lock first if possible @@ -395,8 +389,7 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p if (!p_no_cache) { _remove_from_loading_map(local_path); } - ERR_EXPLAIN("Remapping '" + local_path + "'failed."); - ERR_FAIL_V(RES()); + ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed."); } print_verbose("Loading resource: " + path); @@ -479,10 +472,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ if (!p_no_cache) { bool success = _add_to_loading_map(local_path); - if (!success) { - ERR_EXPLAIN("Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); - ERR_FAIL_V(RES()); - } + ERR_FAIL_COND_V_MSG(!success, RES(), "Resource: '" + local_path + "' is already being loaded. Cyclic reference?"); if (ResourceCache::has(local_path)) { @@ -503,8 +493,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ if (!p_no_cache) { _remove_from_loading_map(local_path); } - ERR_EXPLAIN("Remapping '" + local_path + "'failed."); - ERR_FAIL_V(RES()); + ERR_FAIL_V_MSG(RES(), "Remapping '" + local_path + "' failed."); } print_verbose("Loading resource: " + path); @@ -534,12 +523,9 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ _remove_from_loading_map(local_path); } - if (found) { - ERR_EXPLAIN("Failed loading resource: " + path); - } else { - ERR_EXPLAIN("No loader found for resource: " + path); - } - ERR_FAIL_V(Ref<ResourceInteractiveLoader>()); + ERR_FAIL_COND_V_MSG(found, Ref<ResourceInteractiveLoader>(), "Failed loading resource: " + path + "."); + + ERR_FAIL_V_MSG(Ref<ResourceInteractiveLoader>(), "No loader found for resource: " + path + "."); } void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { @@ -801,7 +787,7 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem if (err == ERR_FILE_EOF) { break; } else if (err != OK) { - ERR_PRINTS("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text); + ERR_PRINTS("Parse error: " + p_path + ".remap:" + itos(lines) + " error: " + error_text + "."); break; } @@ -932,13 +918,11 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader"); - ERR_EXPLAIN("Script does not inherit a CustomResourceLoader: " + script_path); - ERR_FAIL_COND_V(!valid_type, false); + ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceLoader: " + script_path + "."); Object *obj = ClassDB::instance(ibt); - ERR_EXPLAIN("Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt)); - ERR_FAIL_COND_V(obj == NULL, false); + ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + "."); ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj); crl->set_script(s.get_ref_ptr()); diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 369cd93442..a9ad62afe6 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -214,13 +214,11 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver"); - ERR_EXPLAIN("Script does not inherit a CustomResourceSaver: " + script_path); - ERR_FAIL_COND_V(!valid_type, false); + ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + "."); Object *obj = ClassDB::instance(ibt); - ERR_EXPLAIN("Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt)); - ERR_FAIL_COND_V(obj == NULL, false); + ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + "."); ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj); crl->set_script(s.get_ref_ptr()); diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 67a0a905bd..e8e71c10ca 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -67,8 +67,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S if (status == STATUS_READING_ID) { memdelete(f); - ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: "); - ERR_FAIL_V(RES()); + ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: "); } else { break; } @@ -79,8 +78,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S if (status == STATUS_READING_ID) { memdelete(f); - ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: "); - ERR_FAIL_V(RES()); + ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected 'msgid', was expecting 'msgstr' while parsing: "); } if (msg_id != "") { @@ -102,8 +100,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S if (status != STATUS_READING_ID) { memdelete(f); - ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: "); - ERR_FAIL_V(RES()); + ERR_FAIL_V_MSG(RES(), p_path + ":" + itos(line) + " Unexpected 'msgstr', was expecting 'msgid' while parsing: "); } l = l.substr(6, l.length()).strip_edges(); @@ -118,11 +115,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S continue; //nothing to read or comment } - if (!l.begins_with("\"") || status == STATUS_NONE) { - //not a string? failure! - ERR_EXPLAIN(p_path + ":" + itos(line) + " Invalid line '" + l + "' while parsing: "); - ERR_FAIL_V(RES()); - } + ERR_FAIL_COND_V_MSG(!l.begins_with("\"") || status == STATUS_NONE, RES(), p_path + ":" + itos(line) + " Invalid line '" + l + "' while parsing: "); l = l.substr(1, l.length()); //find final quote @@ -135,10 +128,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S } } - if (end_pos == -1) { - ERR_EXPLAIN(p_path + ":" + itos(line) + " Expected '\"' at end of message while parsing file: "); - ERR_FAIL_V(RES()); - } + ERR_FAIL_COND_V_MSG(end_pos == -1, RES(), p_path + ":" + itos(line) + " Expected '\"' at end of message while parsing file: "); l = l.substr(0, end_pos); l = l.c_unescape(); @@ -163,10 +153,7 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S config = msg_str; } - if (config == "") { - ERR_EXPLAIN("No config found in file: " + p_path); - ERR_FAIL_V(RES()); - } + ERR_FAIL_COND_V_MSG(config == "", RES(), "No config found in file: " + p_path + "."); Vector<String> configs = config.split("\n"); for (int i = 0; i < configs.size(); i++) { diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp index 82527d3f38..9487947365 100644 --- a/core/io/xml_parser.cpp +++ b/core/io/xml_parser.cpp @@ -443,10 +443,8 @@ String XMLParser::get_attribute_value(const String &p_name) const { } } - if (idx < 0) { - ERR_EXPLAIN("Attribute not found: " + p_name); - } - ERR_FAIL_COND_V(idx < 0, ""); + ERR_FAIL_COND_V_MSG(idx < 0, "", "Attribute not found: " + p_name + "."); + return attributes[idx].value; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 400f342018..2985959113 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -618,10 +618,7 @@ Basis::operator String() const { Quat Basis::get_quat() const { #ifdef MATH_CHECKS - if (!is_rotation()) { - ERR_EXPLAIN("Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead."); - ERR_FAIL_V(Quat()); - } + 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."); #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; diff --git a/core/math/delaunay.h b/core/math/delaunay.h index ed52c506db..3f8013a3e6 100644 --- a/core/math/delaunay.h +++ b/core/math/delaunay.h @@ -80,11 +80,11 @@ public: } static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) { - if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[0]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[1]]))) { + if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[0]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[1]]) { return true; } - if (Math::is_zero_approx(p_vertices[p_a.edge[0]].distance_to(p_vertices[p_b.edge[1]])) && Math::is_zero_approx(p_vertices[p_a.edge[1]].distance_to(p_vertices[p_b.edge[0]]))) { + if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[1]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[0]]) { return true; } diff --git a/core/math/expression.cpp b/core/math/expression.cpp index 15eea1d308..46f81ce5c3 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -2161,10 +2161,8 @@ Error Expression::parse(const String &p_expression, const Vector<String> &p_inpu } Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) { - if (error_set) { - ERR_EXPLAIN("There was previously a parse error: " + error_str); - ERR_FAIL_V(Variant()); - } + + ERR_FAIL_COND_V_MSG(error_set, Variant(), "There was previously a parse error: " + error_str + "."); execution_error = false; Variant output; @@ -2173,10 +2171,7 @@ Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) { if (err) { execution_error = true; error_str = error_txt; - if (p_show_error) { - ERR_EXPLAIN(error_str); - ERR_FAIL_V(Variant()); - } + ERR_FAIL_COND_V_MSG(p_show_error, Variant(), error_str); } return output; diff --git a/core/math/geometry.h b/core/math/geometry.h index a32ed2f56b..82d9884e9b 100644 --- a/core/math/geometry.h +++ b/core/math/geometry.h @@ -834,8 +834,7 @@ public: static Vector<Vector<Point2> > offset_polyline_2d(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) { - ERR_EXPLAIN("Attempt to offset a polyline like a polygon (use offset_polygon_2d instead)."); - ERR_FAIL_COND_V(p_end_type == END_POLYGON, Vector<Vector<Point2> >()); + ERR_FAIL_COND_V_MSG(p_end_type == END_POLYGON, Vector<Vector<Point2> >(), "Attempt to offset a polyline like a polygon (use offset_polygon_2d instead)."); return _polypath_offset(p_polygon, p_delta, p_join_type, p_end_type); } diff --git a/core/math/octree.h b/core/math/octree.h index e752e10abc..db15c8a1f8 100644 --- a/core/math/octree.h +++ b/core/math/octree.h @@ -564,10 +564,7 @@ void Octree<T, use_pairs, AL>::_ensure_valid_root(const AABB &p_aabb) { while (!base.encloses(p_aabb)) { - if (base.size.x > OCTREE_SIZE_LIMIT) { - ERR_EXPLAIN("Octree upper size limit reeached, does the AABB supplied contain NAN?"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(base.size.x > OCTREE_SIZE_LIMIT, "Octree upper size limit reached, does the AABB supplied contain NAN?"); Octant *gp = memnew_allocator(Octant, AL); octant_count++; diff --git a/core/message_queue.cpp b/core/message_queue.cpp index 32d2b805f6..390989ac91 100644 --- a/core/message_queue.cpp +++ b/core/message_queue.cpp @@ -52,8 +52,7 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName &p_method, const V type = ObjectDB::get_instance(p_id)->get_class(); print_line("Failed method: " + type + ":" + p_method + " target ID: " + itos(p_id)); statistics(); - ERR_EXPLAIN("Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings."); - ERR_FAIL_V(ERR_OUT_OF_MEMORY); + ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings."); } Message *msg = memnew_placement(&buffer[buffer_end], Message); @@ -103,8 +102,7 @@ Error MessageQueue::push_set(ObjectID p_id, const StringName &p_prop, const Vari type = ObjectDB::get_instance(p_id)->get_class(); print_line("Failed set: " + type + ":" + p_prop + " target ID: " + itos(p_id)); statistics(); - ERR_EXPLAIN("Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings."); - ERR_FAIL_V(ERR_OUT_OF_MEMORY); + ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings."); } Message *msg = memnew_placement(&buffer[buffer_end], Message); @@ -136,8 +134,7 @@ Error MessageQueue::push_notification(ObjectID p_id, int p_notification) { type = ObjectDB::get_instance(p_id)->get_class(); print_line("Failed notification: " + itos(p_notification) + " target ID: " + itos(p_id)); statistics(); - ERR_EXPLAIN("Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings."); - ERR_FAIL_V(ERR_OUT_OF_MEMORY); + ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "Message queue out of memory. Try increasing 'message_queue_size_kb' in project settings."); } Message *msg = memnew_placement(&buffer[buffer_end], Message); @@ -256,7 +253,7 @@ void MessageQueue::_call_function(Object *p_target, const StringName &p_func, co p_target->call(p_func, argptrs, p_argcount, ce); if (p_show_error && ce.error != Variant::CallError::CALL_OK) { - ERR_PRINTS("Error calling deferred method: " + Variant::get_call_error_text(p_target, p_func, argptrs, p_argcount, ce)); + ERR_PRINTS("Error calling deferred method: " + Variant::get_call_error_text(p_target, p_func, argptrs, p_argcount, ce) + "."); } } diff --git a/core/node_path.cpp b/core/node_path.cpp index a4b7cbe2eb..8244785d84 100644 --- a/core/node_path.cpp +++ b/core/node_path.cpp @@ -375,8 +375,7 @@ NodePath::NodePath(const String &p_path) { if (str == "") { if (path[i] == 0) continue; // Allow end-of-path : - ERR_EXPLAIN("Invalid NodePath: " + p_path); - ERR_FAIL(); + ERR_FAIL_MSG("Invalid NodePath: " + p_path + "."); } subpath.push_back(str); diff --git a/core/object.cpp b/core/object.cpp index 3367d6b6c3..62bfa31480 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -709,20 +709,17 @@ static void _test_call_error(const StringName &p_func, const Variant::CallError break; case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: { - ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected)); - ERR_FAIL(); + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Invalid type for argument " + itos(error.argument) + ", expected " + Variant::get_type_name(error.expected) + "."); break; } case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument)); - ERR_FAIL(); + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too many arguments, expected " + itos(error.argument) + "."); break; } case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - ERR_EXPLAIN("Error Calling Function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument)); - ERR_FAIL(); + ERR_FAIL_MSG("Error calling function: " + String(p_func) + " - Too few arguments, expected " + itos(error.argument) + "."); break; } case Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL: @@ -739,15 +736,9 @@ void Object::call_multilevel(const StringName &p_method, const Variant **p_args, if (p_method == CoreStringNames::get_singleton()->_free) { #ifdef DEBUG_ENABLED - if (Object::cast_to<Reference>(this)) { - ERR_EXPLAIN("Can't 'free' a reference."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(Object::cast_to<Reference>(this), "Can't 'free' a reference."); - if (_lock_index.get() > 1) { - ERR_EXPLAIN("Object is locked and can't be freed."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(_lock_index.get() > 1, "Object is locked and can't be freed."); #endif //must be here, must be before everything, @@ -835,8 +826,7 @@ Variant Object::callv(const StringName &p_method, const Array &p_args) { Variant::CallError ce; Variant ret = call(p_method, argptrs, p_args.size(), ce); if (ce.error != Variant::CallError::CALL_OK) { - ERR_EXPLAIN("Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce)); - ERR_FAIL_V(Variant()); + ERR_FAIL_V_MSG(Variant(), "Error calling method from 'callv': " + Variant::get_call_error_text(this, p_method, argptrs, p_args.size(), ce) + "."); } return ret; } @@ -888,15 +878,13 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a if (Object::cast_to<Reference>(this)) { r_error.argument = 0; r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - ERR_EXPLAIN("Can't 'free' a reference."); - ERR_FAIL_V(Variant()); + ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); } if (_lock_index.get() > 1) { r_error.argument = 0; r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD; - ERR_EXPLAIN("Object is locked and can't be freed."); - ERR_FAIL_V(Variant()); + ERR_FAIL_V_MSG(Variant(), "Object is locked and can't be freed."); } #endif @@ -1172,10 +1160,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int #ifdef DEBUG_ENABLED bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_name); //check in script - if (!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name)) { - ERR_EXPLAIN("Can't emit non-existing signal " + String("\"") + p_name + "\"."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(!signal_is_valid && !script.is_null() && !Ref<Script>(script)->has_script_signal(p_name), ERR_UNAVAILABLE, "Can't emit non-existing signal " + String("\"") + p_name + "\"."); #endif //not connected? just return return ERR_UNAVAILABLE; @@ -1240,7 +1225,7 @@ Error Object::emit_signal(const StringName &p_name, const Variant **p_args, int if (ce.error == Variant::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) { //most likely object is not initialized yet, do not throw error. } else { - ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce)); + ERR_PRINTS("Error calling method from signal '" + String(p_name) + "': " + Variant::get_call_error_text(target, c.method, args, argc, ce) + "."); err = ERR_METHOD_NOT_FOUND; } } @@ -1415,8 +1400,9 @@ void Object::get_signal_connection_list(const StringName &p_signal, List<Connect p_connections->push_back(s->slot_map.getv(i).conn); } -bool Object::has_persistent_signal_connections() const { +int Object::get_persistent_signal_connection_count() const { + int count = 0; const StringName *S = NULL; while ((S = signal_map.next(S))) { @@ -1424,13 +1410,13 @@ bool Object::has_persistent_signal_connections() const { const Signal *s = &signal_map[*S]; for (int i = 0; i < s->slot_map.size(); i++) { - - if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) - return true; + if (s->slot_map.getv(i).conn.flags & CONNECT_PERSIST) { + count += 1; + } } } - return false; + return count; } void Object::get_signals_connected_to_this(List<Connection> *p_connections) const { @@ -1463,10 +1449,8 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str #endif } - if (!signal_is_valid) { - ERR_EXPLAIN("In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'"); - ERR_FAIL_V(ERR_INVALID_PARAMETER); - } + ERR_FAIL_COND_V_MSG(!signal_is_valid, ERR_INVALID_PARAMETER, "In Object of type '" + String(get_class()) + "': Attempt to connect nonexistent signal '" + p_signal + "' to method '" + p_to_object->get_class() + "." + p_to_method + "'."); + signal_map[p_signal] = Signal(); s = &signal_map[p_signal]; } @@ -1477,8 +1461,7 @@ Error Object::connect(const StringName &p_signal, Object *p_to_object, const Str s->slot_map[target].reference_count++; return OK; } else { - ERR_EXPLAIN("Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); - ERR_FAIL_V(ERR_INVALID_PARAMETER); + ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Signal '" + p_signal + "' is already connected to given method '" + p_to_method + "' in that object."); } } @@ -1514,8 +1497,7 @@ bool Object::is_connected(const StringName &p_signal, Object *p_to_object, const if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)) return false; - ERR_EXPLAIN("Nonexistent signal: " + p_signal); - ERR_FAIL_V(false); + ERR_FAIL_V_MSG(false, "Nonexistent signal: " + p_signal + "."); } Signal::Target target(p_to_object->get_instance_id(), p_to_method); @@ -1533,21 +1515,13 @@ void Object::_disconnect(const StringName &p_signal, Object *p_to_object, const ERR_FAIL_NULL(p_to_object); Signal *s = signal_map.getptr(p_signal); - if (!s) { - ERR_EXPLAIN("Nonexistent signal: " + p_signal); - ERR_FAIL(); - } - if (s->lock > 0) { - ERR_EXPLAIN("Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ")"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!s, "Nonexistent signal: " + p_signal + "."); + + ERR_FAIL_COND_MSG(s->lock > 0, "Attempt to disconnect signal '" + p_signal + "' while emitting (locks: " + itos(s->lock) + ")."); Signal::Target target(p_to_object->get_instance_id(), p_to_method); - if (!s->slot_map.has(target)) { - ERR_EXPLAIN("Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!s->slot_map.has(target), "Disconnecting nonexistent signal '" + p_signal + "', slot: " + itos(target._id) + ":" + target.method + "."); Signal::Slot *slot = &s->slot_map[target]; @@ -1974,10 +1948,7 @@ Object::~Object() { Signal *s = &signal_map[*S]; - if (s->lock) { - ERR_EXPLAIN("Attempt to delete an object in the middle of a signal emission from it"); - ERR_CONTINUE(s->lock > 0); - } + ERR_CONTINUE_MSG(s->lock > 0, "Attempt to delete an object in the middle of a signal emission from it."); //brute force disconnect for performance int slot_count = s->slot_map.size(); diff --git a/core/object.h b/core/object.h index 15c3ab94c5..ac8620757c 100644 --- a/core/object.h +++ b/core/object.h @@ -707,7 +707,7 @@ public: void get_signal_list(List<MethodInfo> *p_signals) const; void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const; void get_all_signal_connections(List<Connection> *p_connections) const; - bool has_persistent_signal_connections() const; + int get_persistent_signal_connection_count() const; void get_signals_connected_to_this(List<Connection> *p_connections) const; Error connect(const StringName &p_signal, Object *p_to_object, const StringName &p_to_method, const Vector<Variant> &p_binds = Vector<Variant>(), uint32_t p_flags = 0); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 7509050b2b..ba94e87da6 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -599,8 +599,7 @@ Vector<uint8_t> FileAccess::get_file_as_array(const String &p_path, Error *r_err if (r_error) { // if error requested, do not throw error return Vector<uint8_t>(); } - ERR_EXPLAIN("Can't open file from path: " + String(p_path)); - ERR_FAIL_V(Vector<uint8_t>()); + 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()); @@ -620,8 +619,7 @@ String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { if (r_error) { return String(); } - ERR_EXPLAIN("Can't get file as string from path: " + String(p_path)); - ERR_FAIL_V(String()); + ERR_FAIL_V_MSG(String(), "Can't get file as string from path: " + String(p_path) + "."); } String ret; diff --git a/core/os/os.cpp b/core/os/os.cpp index 925154af7d..0d7d150914 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -268,8 +268,7 @@ void OS::print_all_resources(String p_to_file) { _OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err); if (err != OK) { _OSPRF = NULL; - ERR_EXPLAIN("Can't print all resources to file: " + String(p_to_file)); - ERR_FAIL(); + ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + "."); } } @@ -487,10 +486,7 @@ void OS::_ensure_user_data_dir() { da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); Error err = da->make_dir_recursive(dd); - if (err != OK) { - ERR_EXPLAIN("Error attempting to create data dir: " + dd); - } - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Error attempting to create data dir: " + dd + "."); memdelete(da); } diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp index 48a30f6702..6c1f2756f2 100644 --- a/core/pool_allocator.cpp +++ b/core/pool_allocator.cpp @@ -204,10 +204,8 @@ PoolAllocator::ID PoolAllocator::alloc(int p_size) { /* Then search again */ if (!find_hole(&new_entry_indices_pos, size_to_alloc)) { - mt_unlock(); - ERR_EXPLAIN("Memory can't be compacted further"); - ERR_FAIL_V(POOL_ALLOCATOR_INVALID_ID); + ERR_FAIL_V_MSG(POOL_ALLOCATOR_INVALID_ID, "Memory can't be compacted further."); } } @@ -217,8 +215,7 @@ PoolAllocator::ID PoolAllocator::alloc(int p_size) { if (!found_free_entry) { mt_unlock(); - ERR_EXPLAIN("No free entry found in PoolAllocator"); - ERR_FAIL_V(POOL_ALLOCATOR_INVALID_ID); + ERR_FAIL_V_MSG(POOL_ALLOCATOR_INVALID_ID, "No free entry found in PoolAllocator."); } /* move all entry indices up, make room for this one */ diff --git a/core/pool_vector.cpp b/core/pool_vector.cpp index b9d2316315..50ea898bef 100644 --- a/core/pool_vector.cpp +++ b/core/pool_vector.cpp @@ -66,6 +66,5 @@ void MemoryPool::cleanup() { memdelete_arr(allocs); memdelete(alloc_mutex); - ERR_EXPLAINC("There are still MemoryPool allocs in use at exit!"); - ERR_FAIL_COND(allocs_used > 0); + ERR_FAIL_COND_MSG(allocs_used > 0, "There are still MemoryPool allocs in use at exit!"); } diff --git a/core/pool_vector.h b/core/pool_vector.h index 39a8eccc51..957a72483c 100644 --- a/core/pool_vector.h +++ b/core/pool_vector.h @@ -98,8 +98,7 @@ class PoolVector { MemoryPool::alloc_mutex->lock(); if (MemoryPool::allocs_used == MemoryPool::alloc_count) { MemoryPool::alloc_mutex->unlock(); - ERR_EXPLAINC("All memory pool allocations are in use, can't COW."); - ERR_FAIL(); + ERR_FAIL_MSG("All memory pool allocations are in use, can't COW."); } MemoryPool::Alloc *old_alloc = alloc; @@ -520,8 +519,7 @@ Error PoolVector<T>::resize(int p_size) { MemoryPool::alloc_mutex->lock(); if (MemoryPool::allocs_used == MemoryPool::alloc_count) { MemoryPool::alloc_mutex->unlock(); - ERR_EXPLAINC("All memory pool allocations are in use."); - ERR_FAIL_V(ERR_OUT_OF_MEMORY); + ERR_FAIL_V_MSG(ERR_OUT_OF_MEMORY, "All memory pool allocations are in use."); } //take one from the free list diff --git a/core/project_settings.cpp b/core/project_settings.cpp index c1d4967f55..0a673fb638 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -500,8 +500,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) { if (hdr[0] != 'E' || hdr[1] != 'C' || hdr[2] != 'F' || hdr[3] != 'G') { memdelete(f); - ERR_EXPLAIN("Corrupted header in binary project.binary (not ECFG)"); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Corrupted header in binary project.binary (not ECFG)."); } uint32_t count = f->get_32(); @@ -522,8 +521,7 @@ Error ProjectSettings::_load_settings_binary(const String &p_path) { f->get_buffer(d.ptrw(), vlen); Variant value; err = decode_variant(value, d.ptr(), d.size(), NULL, true); - ERR_EXPLAIN("Error decoding property: " + key); - ERR_CONTINUE(err != OK); + ERR_CONTINUE_MSG(err != OK, "Error decoding property: " + key + "."); set(key, value); } @@ -577,8 +575,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) { config_version = value; if (config_version > CONFIG_VERSION) { memdelete(f); - ERR_EXPLAIN(vformat("Can't open project at '%s', its `config_version` (%d) is from a more recent and incompatible version of the engine. Expected config version: %d.", p_path, config_version, CONFIG_VERSION)); - ERR_FAIL_V(ERR_FILE_CANT_OPEN); + ERR_FAIL_V_MSG(ERR_FILE_CANT_OPEN, vformat("Can't open project at '%s', its `config_version` (%d) is from a more recent and incompatible version of the engine. Expected config version: %d.", p_path, config_version, CONFIG_VERSION)); } } else { if (section == String()) { @@ -645,11 +642,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str Error err; FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); - if (err != OK) { - - ERR_EXPLAIN("Couldn't save project.binary at " + p_file); - ERR_FAIL_COND_V(err, err); - } + ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.binary at " + p_file + "."); uint8_t hdr[4] = { 'E', 'C', 'F', 'G' }; file->store_buffer(hdr, 4); @@ -738,10 +731,7 @@ Error ProjectSettings::_save_settings_text(const String &p_file, const Map<Strin Error err; FileAccess *file = FileAccess::open(p_file, FileAccess::WRITE, &err); - if (err) { - ERR_EXPLAIN("Couldn't save project.godot - " + p_file); - ERR_FAIL_COND_V(err, err); - } + ERR_FAIL_COND_V_MSG(err != OK, err, "Couldn't save project.godot - " + p_file + "."); file->store_line("; Engine configuration file."); file->store_line("; It's best edited using the editor UI and not directly,"); @@ -872,8 +862,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust return _save_settings_binary(p_path, props, p_custom, custom_features); else { - ERR_EXPLAIN("Unknown config file format: " + p_path); - ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Unknown config file format: " + p_path + "."); } } diff --git a/core/resource.cpp b/core/resource.cpp index 74e2c1ed6b..5a5efa4644 100644 --- a/core/resource.cpp +++ b/core/resource.cpp @@ -75,8 +75,7 @@ void Resource::set_path(const String &p_path, bool p_take_over) { bool exists = ResourceCache::resources.has(p_path); ResourceCache::lock->read_unlock(); - ERR_EXPLAIN("Another resource is loaded from path: " + p_path + " (possible cyclic resource inclusion)"); - ERR_FAIL_COND(exists); + ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path: " + p_path + " (possible cyclic resource inclusion)."); } } path_cache = p_path; @@ -277,8 +276,7 @@ void Resource::notify_change_to_owners() { for (Set<ObjectID>::Element *E = owners.front(); E; E = E->next()) { Object *obj = ObjectDB::get_instance(E->get()); - ERR_EXPLAIN("Object was deleted, while still owning a resource"); - ERR_CONTINUE(!obj); //wtf + ERR_CONTINUE_MSG(!obj, "Object was deleted, while still owning a resource."); //wtf //TODO store string obj->call("resource_changed", RES(this)); } @@ -427,7 +425,7 @@ Resource::~Resource() { ResourceCache::lock->write_unlock(); } if (owners.size()) { - WARN_PRINT("Resource is still owned"); + WARN_PRINT("Resource is still owned."); } } diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 6dd9054aaa..2a061f0947 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -89,7 +89,7 @@ Error ScriptDebuggerRemote::connect_to_host(const String &p_host, uint16_t p_por if (tcp_client->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - ERR_PRINTS("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status())); + ERR_PRINTS("Remote Debugger: Unable to connect. Status: " + String::num(tcp_client->get_status()) + "."); return FAILED; }; @@ -110,7 +110,7 @@ void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_ int len = 0; Error err = encode_variant(var, NULL, len, true); if (err != OK) - ERR_PRINT("Failed to encode variant"); + ERR_PRINT("Failed to encode variant."); if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size packet_peer_stream->put_var(Variant()); @@ -134,10 +134,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) //this function is called when there is a debugger break (bug on script) //or when execution is paused from editor - if (!tcp_client->is_connected_to_host()) { - ERR_EXPLAIN("Script Debugger failed to connect, but being used anyway."); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!tcp_client->is_connected_to_host(), "Script Debugger failed to connect, but being used anyway."); packet_peer_stream->put_var("debug_enter"); packet_peer_stream->put_var(2); diff --git a/core/translation.cpp b/core/translation.cpp index a3ff971f45..a0902d71fc 100644 --- a/core/translation.cpp +++ b/core/translation.cpp @@ -848,8 +848,7 @@ void Translation::set_locale(const String &p_locale) { if (!TranslationServer::is_locale_valid(univ_locale)) { String trimmed_locale = get_trimmed_locale(univ_locale); - ERR_EXPLAIN("Invalid locale: " + trimmed_locale); - ERR_FAIL_COND(!TranslationServer::is_locale_valid(trimmed_locale)); + ERR_FAIL_COND_MSG(!TranslationServer::is_locale_valid(trimmed_locale), "Invalid locale: " + trimmed_locale + "."); locale = trimmed_locale; } else { diff --git a/core/variant.cpp b/core/variant.cpp index 1574af5239..e7d0e58367 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1740,10 +1740,7 @@ Variant::operator RID() const { } else if (type == OBJECT && _get_obj().obj) { #ifdef DEBUG_ENABLED if (ScriptDebugger::get_singleton()) { - if (!ObjectDB::instance_validate(_get_obj().obj)) { - ERR_EXPLAIN("Invalid pointer (object was deleted)"); - ERR_FAIL_V(RID()); - }; + ERR_FAIL_COND_V_MSG(!ObjectDB::instance_validate(_get_obj().obj), RID(), "Invalid pointer (object was deleted)."); }; #endif Variant::CallError ce; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index eca5d0567b..9ea2fed5ae 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -584,8 +584,7 @@ struct _VariantCall { if (buffer_size < 0) { r_ret = decompressed; - ERR_EXPLAIN("Decompression buffer size is less than zero"); - ERR_FAIL(); + ERR_FAIL_MSG("Decompression buffer size is less than zero."); } decompressed.resize(buffer_size); diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index b4c44fe8eb..e510603281 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -165,6 +165,7 @@ </argument> <description> Queues an animation for playback once the current one is done. + [b]Note:[/b] If a looped animation is currently playing, the queued animation will never play unless the looped animation is stopped somehow. </description> </method> <method name="remove_animation"> diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml index b7b77bc02a..fd08643dd5 100644 --- a/doc/classes/ClassDB.xml +++ b/doc/classes/ClassDB.xml @@ -134,7 +134,7 @@ <argument index="2" name="no_inheritance" type="bool" default="false"> </argument> <description> - Returns whether [code]class[/code] (or its ancestry if [code]no_inheritance[/code] is false) has a method called [code]method[/code] or not. + Returns whether [code]class[/code] (or its ancestry if [code]no_inheritance[/code] is [code]false[/code]) has a method called [code]method[/code] or not. </description> </method> <method name="class_has_signal" qualifiers="const"> @@ -201,7 +201,7 @@ <argument index="0" name="class" type="String"> </argument> <description> - Returns whether this class is enabled or not. + Returns whether this [code]class[/code] is enabled or not. </description> </method> <method name="is_parent_class" qualifiers="const"> diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml index 9294a515d2..8aae85563a 100644 --- a/doc/classes/Directory.xml +++ b/doc/classes/Directory.xml @@ -127,8 +127,8 @@ </argument> <description> Initializes the stream used to list all files and directories using the [method get_next] function, closing the current opened stream if needed. Once the stream has been processed, it should typically be closed with [method list_dir_end]. - If you pass [code]skip_navigational[/code], then [code].[/code] and [code]..[/code] would be filtered out. - If you pass [code]skip_hidden[/code], then hidden files would be filtered out. + If [code]skip_navigational[/code] is [code]true[/code], [code].[/code] and [code]..[/code] are filtered out. + If [code]skip_hidden[/code] is [code]true[/code], hidden files are filtered out. </description> </method> <method name="list_dir_end"> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index 91ebcd52f6..33b9da6fdf 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -20,6 +20,7 @@ <description> This will simulate pressing the specified action. The strength can be used for non-boolean actions, it's ranged between 0 and 1 representing the intensity of the given action. + [b]Note:[/b] This method will not cause any [method Node._input] calls. It is intended to be used with [method is_action_pressed] and [method is_action_just_pressed]. If you want to simulate [code]_input[/code], use [method parse_input_event] instead. </description> </method> <method name="action_release"> @@ -283,7 +284,14 @@ <argument index="0" name="event" type="InputEvent"> </argument> <description> - Feeds an [InputEvent] to the game. Can be used to artificially trigger input events from code. + Feeds an [InputEvent] to the game. Can be used to artificially trigger input events from code. Also generates [method Node._input] calls. + Example: + [codeblock] + var a = InputEventAction.new() + a.action = "ui_cancel" + a.pressed = true + Input.parse_input_event(a) + [/codeblock] </description> </method> <method name="remove_joy_mapping"> diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml index f5bf12a876..fedf77bfd2 100644 --- a/doc/classes/MainLoop.xml +++ b/doc/classes/MainLoop.xml @@ -4,7 +4,7 @@ Abstract base class for the game's main loop. </brief_description> <description> - [MainLoop] is the abstract base class for a Godot project's game loop. It in inherited by [SceneTree], which is the default game loop implementation used in Godot projects, though it is also possible to write and use one's own [MainLoop] subclass instead of the scene tree. + [MainLoop] is the abstract base class for a Godot project's game loop. It is inherited by [SceneTree], which is the default game loop implementation used in Godot projects, though it is also possible to write and use one's own [MainLoop] subclass instead of the scene tree. Upon the application start, a [MainLoop] implementation must be provided to the OS; otherwise, the application will exit. This happens automatically (and a [SceneTree] is created) unless a main [Script] is provided from the command line (with e.g. [code]godot -s my_loop.gd[/code], which should then be a [MainLoop] implementation. Here is an example script implementing a simple [MainLoop]: [codeblock] diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 4716b29e03..6be48a4c58 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -1265,14 +1265,11 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur void RasterizerCanvasGLES2::_copy_screen(const Rect2 &p_rect) { if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen"); + ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen."); return; } - if (storage->frame.current_rt->copy_screen_effect.color == 0) { - ERR_EXPLAIN("Can't use screen texture copying in a render target configured without copy buffers"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(storage->frame.current_rt->copy_screen_effect.color == 0, "Can't use screen texture copying in a render target configured without copy buffers."); glDisable(GL_BLEND); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 453abeb853..cc414c26af 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -882,8 +882,7 @@ RID RasterizerSceneGLES2::light_instance_create(RID p_light) { if (!light_instance->light_ptr) { memdelete(light_instance); - ERR_EXPLAIN("Condition ' !light_instance->light_ptr ' is true."); - ERR_FAIL_V(RID()); + ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); } light_instance->self = light_instance_owner.make_rid(light_instance); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index a30af87516..8e026b96ce 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -2171,8 +2171,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: //must have index and bones, both. { uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS; - ERR_EXPLAIN("Array must have both bones and weights in format or none."); - ERR_FAIL_COND((p_format & bones_weight) && (p_format & bones_weight) != bones_weight); + ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none."); } //bool has_morph = p_blend_shapes.size(); @@ -3497,6 +3496,8 @@ RID RasterizerStorageGLES2::skeleton_create() { Skeleton *skeleton = memnew(Skeleton); + glGenTextures(1, &skeleton->tex_id); + return skeleton_owner.make_rid(skeleton); } @@ -3514,7 +3515,6 @@ void RasterizerStorageGLES2::skeleton_allocate(RID p_skeleton, int p_bones, bool skeleton->use_2d = p_2d_skeleton; if (config.float_texture_supported) { - glGenTextures(1, &skeleton->tex_id); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 9c9a8e9717..40574d8c77 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -758,11 +758,13 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::OP_SELECT_IF: { + code += "("; code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += " ? "; code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += " : "; code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")"; } break; case SL::OP_MOD: { diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 1a97225e6b..edffe852a2 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1156,10 +1156,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur void RasterizerCanvasGLES3::_copy_texscreen(const Rect2 &p_rect) { - if (storage->frame.current_rt->effects.mip_maps[0].sizes.size() == 0) { - ERR_EXPLAIN("Can't use screen texture copying in a render target configured without copy buffers"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(storage->frame.current_rt->effects.mip_maps[0].sizes.size() == 0, "Can't use screen texture copying in a render target configured without copy buffers."); glDisable(GL_BLEND); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 30ca07aa28..1472954ebc 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1008,8 +1008,7 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { if (!light_instance->light_ptr) { memdelete(light_instance); - ERR_EXPLAIN("Condition ' !light_instance->light_ptr ' is true."); - ERR_FAIL_V(RID()); + ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); } light_instance->self = light_instance_owner.make_rid(light_instance); @@ -1121,13 +1120,23 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m if (state.current_depth_draw != p_material->shader->spatial.depth_draw_mode) { switch (p_material->shader->spatial.depth_draw_mode) { - case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: + case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: { + glDepthMask(GL_TRUE); + // If some transparent objects write to depth, we need to re-copy depth texture when we need it + if (p_alpha_pass && !state.used_depth_prepass) { + state.prepared_depth_texture = false; + } + } break; case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_OPAQUE: { glDepthMask(!p_alpha_pass); } break; case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALWAYS: { glDepthMask(GL_TRUE); + // If some transparent objects write to depth, we need to re-copy depth texture when we need it + if (p_alpha_pass) { + state.prepared_depth_texture = false; + } } break; case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER: { glDepthMask(GL_FALSE); @@ -4616,6 +4625,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const return; } + if (env && (env->dof_blur_far_enabled || env->dof_blur_near_enabled) && storage->frame.current_rt && storage->frame.current_rt->buffers.active) + _prepare_depth_texture(); _post_process(env, p_cam_projection); // Needed only for debugging /* if (shadow_atlas && storage->frame.current_rt) { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index c7040c232b..a54064e4c8 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -3191,8 +3191,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: //must have index and bones, both. { uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS; - ERR_EXPLAIN("Array must have both bones and weights in format or none."); - ERR_FAIL_COND((p_format & bones_weight) && (p_format & bones_weight) != bones_weight); + ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none."); } //bool has_morph = p_blend_shapes.size(); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 6b477ec78b..85ace4b4f0 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -772,11 +772,13 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::OP_SELECT_IF: { + code += "("; code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "?"; code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += ":"; code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")"; } break; diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp index 0e849bf2fe..7deac1d118 100644 --- a/drivers/png/png_driver_common.cpp +++ b/drivers/png/png_driver_common.cpp @@ -97,7 +97,7 @@ Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { break; default: png_image_free(&png_img); // only required when we return before finish_read - ERR_PRINT("Unsupported png format"); + ERR_PRINT("Unsupported png format."); return ERR_UNAVAILABLE; } @@ -179,10 +179,9 @@ Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer) { ERR_FAIL_COND_V(check_error(png_img), FAILED); } if (!success) { - if (compressed_size <= png_size_estimate) { - // buffer was big enough, must be some other error - ERR_FAIL_V(FAILED); - } + + // buffer was big enough, must be some other error + ERR_FAIL_COND_V(compressed_size <= png_size_estimate, FAILED); // write failed due to buffer size, resize and retry Error err = p_buffer.resize(buffer_offset + compressed_size); diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index 43a30f055b..7a2eeafdc3 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -39,9 +39,8 @@ Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32 Ref<ImageTexture> texture = p_resource; - ERR_FAIL_COND_V(!texture.is_valid(), ERR_INVALID_PARAMETER); - ERR_EXPLAIN("Can't save empty texture as PNG"); - ERR_FAIL_COND_V(!texture->get_width() || !texture->get_height(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as PNG."); + ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as PNG."); Ref<Image> img = texture->get_data(); diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index a285b3b65f..5820a59019 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -288,8 +288,7 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { if (!err) { return flags.st_mtime; } else { - ERR_EXPLAIN("Failed to get modified time for: " + p_file); - ERR_FAIL_V(0); + ERR_FAIL_V_MSG(0, "Failed to get modified time for: " + p_file + "."); }; } @@ -302,8 +301,7 @@ uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) { if (!err) { return flags.st_mode & 0x7FF; //only permissions } else { - ERR_EXPLAIN("Failed to get unix permissions for: " + p_file); - ERR_FAIL_V(0); + ERR_FAIL_V_MSG(0, "Failed to get unix permissions for: " + p_file + "."); }; } diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index ce66f07a19..ac7195abc1 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -184,9 +184,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co continue; // will go back and alloc the right size }; - ERR_EXPLAIN("Call to GetAdaptersAddresses failed with error " + itos(err)); - ERR_FAIL(); - return; + ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + "."); }; IP_ADAPTER_ADDRESSES *adapter = addrs; diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index aa61cf5dcc..ab5590dba4 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -72,8 +72,7 @@ static double _clock_scale = 0; static void _setup_clock() { mach_timebase_info_data_t info; kern_return_t ret = mach_timebase_info(&info); - ERR_EXPLAIN("OS CLOCK IS NOT WORKING!"); - ERR_FAIL_COND(ret != 0); + ERR_FAIL_COND_MSG(ret != 0, "OS CLOCK IS NOT WORKING!"); _clock_scale = ((double)info.numer / (double)info.denom) / 1000.0; _clock_start = mach_absolute_time() * _clock_scale; } @@ -85,8 +84,7 @@ static void _setup_clock() { #endif static void _setup_clock() { struct timespec tv_now = { 0, 0 }; - ERR_EXPLAIN("OS CLOCK IS NOT WORKING!"); - ERR_FAIL_COND(clock_gettime(GODOT_CLOCK, &tv_now) != 0); + ERR_FAIL_COND_MSG(clock_gettime(GODOT_CLOCK, &tv_now) != 0, "OS CLOCK IS NOT WORKING!"); _clock_start = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L; } #endif @@ -420,10 +418,7 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); - if (!p_library_handle) { - ERR_EXPLAIN("Can't open dynamic library: " + p_path + ". Error: " + dlerror()); - ERR_FAIL_V(ERR_CANT_OPEN); - } + ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror()); return OK; } @@ -442,12 +437,9 @@ Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const S error = dlerror(); if (error != NULL) { - if (!p_optional) { - ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + error); - ERR_FAIL_V(ERR_CANT_RESOLVE); - } else { - return ERR_CANT_RESOLVE; - } + ERR_FAIL_COND_V_MSG(!p_optional, ERR_CANT_RESOLVE, "Can't resolve symbol " + p_name + ". Error: " + error + "."); + + return ERR_CANT_RESOLVE; } return OK; } diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index b0f102f1a3..adc3cc8d65 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -296,8 +296,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c } hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL); - ERR_EXPLAIN("WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16)); - ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + "."); if (p_capture) { hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client); diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 646e744248..c12a2d75a8 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -125,6 +125,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { return OK; } } + void FileAccessWindows::close() { if (!f) @@ -167,13 +168,11 @@ void FileAccessWindows::close() { if (close_fail_notify) { close_fail_notify(save_path); } - - ERR_EXPLAIN("Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash."); } save_path = ""; - ERR_FAIL_COND(rename_error); + ERR_FAIL_COND_MSG(rename_error, "Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash."); } } @@ -334,8 +333,7 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) { return st.st_mtime; } else { - ERR_EXPLAIN("Failed to get modified time for: " + file); - ERR_FAIL_V(0); + ERR_FAIL_V_MSG(0, "Failed to get modified time for: " + file + "."); } } diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index 8674d24af6..6d729c50ab 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -63,15 +63,10 @@ Error AudioDriverXAudio2::init() { HRESULT hr; hr = XAudio2Create(&xaudio, 0, XAUDIO2_DEFAULT_PROCESSOR); - if (hr != S_OK) { - ERR_EXPLAIN("Error creating XAudio2 engine."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 engine."); + hr = xaudio->CreateMasteringVoice(&mastering_voice); - if (hr != S_OK) { - ERR_EXPLAIN("Error creating XAudio2 mastering voice."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 mastering voice."); wave_format.nChannels = channels; wave_format.cbSize = 0; @@ -82,10 +77,7 @@ Error AudioDriverXAudio2::init() { wave_format.nAvgBytesPerSec = mix_rate * wave_format.nBlockAlign; hr = xaudio->CreateSourceVoice(&source_voice, &wave_format, 0, XAUDIO2_MAX_FREQ_RATIO, &voice_callback); - if (hr != S_OK) { - ERR_EXPLAIN("Error creating XAudio2 source voice. " + itos(hr)); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 source voice. Error code: " + itos(hr) + "."); mutex = Mutex::create(); thread = Thread::create(AudioDriverXAudio2::thread_func, this); @@ -140,10 +132,7 @@ void AudioDriverXAudio2::start() { active = true; HRESULT hr = source_voice->Start(0); - if (hr != S_OK) { - ERR_EXPLAIN("XAudio2 start error " + itos(hr)); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); } int AudioDriverXAudio2::get_mix_rate() const { diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 014bb08144..c93dc2b340 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1748,7 +1748,11 @@ void AnimationTimelineEdit::_play_position_draw() { if (px >= get_name_limit() && px < (play_position->get_size().width - get_buttons_width())) { Color color = get_color("accent_color", "Editor"); - play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE)); + play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE)); + play_position->draw_texture( + get_icon("TimelineIndicator", "EditorIcons"), + Point2(px - get_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0), + color); } } @@ -2438,7 +2442,7 @@ void AnimationTrackEdit::_play_position_draw() { if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) { Color color = get_color("accent_color", "Editor"); - play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE)); + play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE)); } } @@ -3184,7 +3188,7 @@ void AnimationTrackEditGroup::_notification(int p_what) { if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) { Color accent = get_color("accent_color", "Editor"); - draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(EDSCALE)); + draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(2 * EDSCALE)); } } } @@ -5050,10 +5054,9 @@ float AnimationTrackEditor::get_moving_selection_offset() const { void AnimationTrackEditor::_box_selection_draw() { - Color color = get_color("accent_color", "Editor"); - color.a = 0.2; - Rect2 rect = Rect2(Point2(), box_selection->get_size()); - box_selection->draw_rect(rect, color); + const Rect2 selection_rect = Rect2(Point2(), box_selection->get_size()); + box_selection->draw_rect(selection_rect, get_color("box_selection_fill_color", "Editor")); + box_selection->draw_rect(selection_rect, get_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE)); } void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index edd59f3057..aea7f461f1 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -1903,8 +1903,7 @@ void Collada::_parse_animation(XMLParser &parser) { Vector<float> &output = float_sources[output_id]; - ERR_EXPLAIN("Wrong number of keys in output"); - ERR_CONTINUE((output.size() / stride) != key_count); + ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output."); for (int j = 0; j < key_count; j++) { track.keys.write[j].data.resize(output_len); @@ -2447,8 +2446,7 @@ void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) { state.morph_ownership_map[base] = nj->id; break; } else { - ERR_EXPLAIN("Invalid scene"); - ERR_FAIL(); + ERR_FAIL_MSG("Invalid scene."); } } } diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 48bc409b73..c5b81c4685 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -881,7 +881,6 @@ void ConnectionsDock::update_tree() { icon = get_icon(scr->get_class(), "EditorIcons"); } } - } else { ClassDB::get_signal_list(base, &node_signals2, true); @@ -891,6 +890,10 @@ void ConnectionsDock::update_tree() { name = base; } + if (!icon.is_valid()) { + icon = get_icon("Object", "EditorIcons"); + } + TreeItem *pitem = NULL; if (node_signals2.size()) { @@ -939,7 +942,7 @@ void ConnectionsDock::update_tree() { item->set_metadata(0, sinfo); item->set_icon(0, get_icon("Signal", "EditorIcons")); - // Set tooltip with the signal's documentation + // Set tooltip with the signal's documentation. { String descr; bool found = false; diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 5b8c8fffb8..0f99e2ba1e 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -720,8 +720,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & methods.push_back(method); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + parser->get_node_name()); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section) @@ -841,8 +840,7 @@ Error DocData::_load(Ref<XMLParser> parser) { if (parser->get_node_type() == XMLParser::NODE_TEXT) c.tutorials.push_back(parser->get_node_data().strip_edges()); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "tutorials") break; //end of <tutorials> @@ -883,8 +881,7 @@ Error DocData::_load(Ref<XMLParser> parser) { prop2.description = parser->get_node_data(); c.properties.push_back(prop2); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "members") @@ -912,8 +909,7 @@ Error DocData::_load(Ref<XMLParser> parser) { prop2.description = parser->get_node_data(); c.theme_properties.push_back(prop2); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "theme_items") @@ -943,8 +939,7 @@ Error DocData::_load(Ref<XMLParser> parser) { constant2.description = parser->get_node_data(); c.constants.push_back(constant2); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "constants") @@ -953,8 +948,7 @@ Error DocData::_load(Ref<XMLParser> parser) { } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name2); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name2 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "class") @@ -991,10 +985,8 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri Error err; String save_file = save_path.plus_file(c.name + ".xml"); FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err); - if (err) { - ERR_EXPLAIN("Can't write doc file: " + save_file); - ERR_CONTINUE(err); - } + + ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + "."); _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 7210211d90..555a7f99c8 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -315,8 +315,7 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { RES res = ResourceLoader::load(p_path); - ERR_EXPLAIN("Can't autoload: " + p_path); - ERR_FAIL_COND_V(res.is_null(), NULL); + ERR_FAIL_COND_V_MSG(res.is_null(), NULL, "Can't autoload: " + p_path + "."); Node *n = NULL; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; @@ -325,20 +324,17 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_EXPLAIN("Script does not inherit a Node: " + p_path); - ERR_FAIL_COND_V(!valid_type, NULL); + ERR_FAIL_COND_V_MSG(!valid_type, NULL, "Script does not inherit a Node: " + p_path + "."); Object *obj = ClassDB::instance(ibt); - ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); - ERR_FAIL_COND_V(obj == NULL, NULL); + ERR_FAIL_COND_V_MSG(obj == NULL, NULL, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + "."); n = Object::cast_to<Node>(obj); n->set_script(s.get_ref_ptr()); } - ERR_EXPLAIN("Path in autoload not a node or script: " + p_path); - ERR_FAIL_COND_V(!n, NULL); + ERR_FAIL_COND_V_MSG(!n, NULL, "Path in autoload not a node or script: " + p_path + "."); return n; } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index f5846c10f6..c98635d16b 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -537,6 +537,7 @@ int EditorData::add_edited_scene(int p_at_pos) { p_at_pos = edited_scene.size(); EditedScene es; es.root = NULL; + es.path = String(); es.history_current = -1; es.version = 0; es.live_edit_root = NodePath(String("/root")); @@ -653,6 +654,8 @@ bool EditorData::check_and_update_scene(int p_idx) { memdelete(edited_scene[p_idx].root); edited_scene.write[p_idx].root = new_scene; + if (new_scene->get_filename() != "") + edited_scene.write[p_idx].path = new_scene->get_filename(); edited_scene.write[p_idx].selection = new_selection; return true; @@ -684,6 +687,12 @@ void EditorData::set_edited_scene_root(Node *p_root) { ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); edited_scene.write[current_edited_scene].root = p_root; + if (p_root) { + if (p_root->get_filename() != "") + edited_scene.write[current_edited_scene].path = p_root->get_filename(); + else + p_root->set_filename(edited_scene[current_edited_scene].path); + } } int EditorData::get_edited_scene_count() const { @@ -773,6 +782,7 @@ String EditorData::get_scene_title(int p_idx) const { void EditorData::set_scene_path(int p_idx, const String &p_path) { ERR_FAIL_INDEX(p_idx, edited_scene.size()); + edited_scene.write[p_idx].path = p_path; if (!edited_scene[p_idx].root) return; @@ -783,9 +793,14 @@ String EditorData::get_scene_path(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String()); - if (!edited_scene[p_idx].root) - return ""; - return edited_scene[p_idx].root->get_filename(); + if (edited_scene[p_idx].root) { + if (edited_scene[p_idx].root->get_filename() == "") + edited_scene[p_idx].root->set_filename(edited_scene[p_idx].path); + else + return edited_scene[p_idx].root->get_filename(); + } + + return edited_scene[p_idx].path; } void EditorData::set_edited_scene_live_edit_root(const NodePath &p_root) { diff --git a/editor/editor_data.h b/editor/editor_data.h index 845878e070..df83135942 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -117,6 +117,7 @@ public: struct EditedScene { Node *root; + String path; Dictionary editor_states; List<Node *> selection; Vector<EditorHistory::History> history_stored; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index e1f2635275..cb1754bb10 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -1011,7 +1011,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c if (!ftmp) { memdelete(f); DirAccess::remove_file_or_error(tmppath); - ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path: " + String(tmppath)); + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path: " + String(tmppath) + "."); } const int bufsize = 16384; diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 1f43740858..8c9aedc7b7 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -257,6 +257,7 @@ void EditorFileDialog::_post_popup() { if (is_visible_in_tree()) { Ref<Texture> folder = get_icon("folder", "FileDialog"); + const Color folder_color = get_color("folder", "FileDialog"); recent->clear(); bool res = access == ACCESS_RESOURCES; @@ -274,6 +275,7 @@ void EditorFileDialog::_post_popup() { recent->add_item(name, folder); recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]); + recent->set_item_icon_modulate(recent->get_item_count() - 1, folder_color); } local_history.clear(); @@ -734,6 +736,7 @@ void EditorFileDialog::update_file_list() { dir_access->list_dir_begin(); Ref<Texture> folder = get_icon("folder", "FileDialog"); + const Color folder_color = get_color("folder", "FileDialog"); List<String> files; List<String> dirs; @@ -774,6 +777,7 @@ void EditorFileDialog::update_file_list() { d["dir"] = true; item_list->set_item_metadata(item_list->get_item_count() - 1, d); + item_list->set_item_icon_modulate(item_list->get_item_count() - 1, folder_color); dirs.pop_front(); } @@ -1200,6 +1204,7 @@ void EditorFileDialog::_update_favorites() { String current = get_current_dir(); Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons"); + const Color folder_color = get_color("folder", "FileDialog"); favorites->clear(); favorite->set_pressed(false); @@ -1230,6 +1235,7 @@ void EditorFileDialog::_update_favorites() { } favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]); + favorites->set_item_icon_modulate(favorites->get_item_count() - 1, folder_color); if (setthis) { favorite->set_pressed(true); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index be3df2815e..6d3377a85b 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1930,8 +1930,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { Error err = da->make_dir(".import"); if (err) { memdelete(da); - ERR_EXPLAIN("Failed to create 'res://.import' folder."); - ERR_FAIL(); + ERR_FAIL_MSG("Failed to create 'res://.import' folder."); } } memdelete(da); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 866a90ff10..5ec071d71a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1926,10 +1926,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { switch (p_option) { case FILE_NEW_SCENE: { - int idx = editor_data.add_edited_scene(-1); - _scene_tab_changed(idx); - editor_data.clear_editor_states(); - _update_scene_tabs(); + new_scene(); } break; case FILE_NEW_INHERITED_SCENE: @@ -2798,8 +2795,7 @@ void EditorNode::select_editor_by_name(const String &p_name) { } } - ERR_EXPLAIN("The editor name '" + p_name + "' was not found."); - ERR_FAIL(); + ERR_FAIL_MSG("The editor name '" + p_name + "' was not found."); } void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { @@ -2925,31 +2921,35 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, return; } - String path = cf->get_value("plugin", "script"); - path = String("res://addons").plus_file(p_addon).plus_file(path); + String script_path = cf->get_value("plugin", "script"); + Ref<Script> script; // We need to save it for creating "ep" below. - Ref<Script> script = ResourceLoader::load(path); + // Only try to load the script if it has a name. Else, the plugin has no init script. + if (script_path.length() > 0) { + script_path = String("res://addons").plus_file(p_addon).plus_file(script_path); + script = ResourceLoader::load(script_path); - if (script.is_null()) { - show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), path)); - return; - } + if (script.is_null()) { + show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), script_path)); + return; + } - //errors in the script cause the base_type to be "" - if (String(script->get_instance_base_type()) == "") { - show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), path)); - return; - } + // Errors in the script cause the base_type to be an empty string. + if (String(script->get_instance_base_type()) == "") { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), script_path)); + return; + } - //could check inheritance.. - if (String(script->get_instance_base_type()) != "EditorPlugin") { - show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), path)); - return; - } + // Plugin init scripts must inherit from EditorPlugin and be tools. + if (String(script->get_instance_base_type()) != "EditorPlugin") { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), script_path)); + return; + } - if (!script->is_tool()) { - show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), path)); - return; + if (!script->is_tool()) { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), script_path)); + return; + } } EditorPlugin *ep = memnew(EditorPlugin); @@ -3162,6 +3162,14 @@ void EditorNode::fix_dependencies(const String &p_for_file) { dependency_fixer->edit(p_for_file); } +int EditorNode::new_scene() { + int idx = editor_data.add_edited_scene(-1); + _scene_tab_changed(idx); + editor_data.clear_editor_states(); + _update_scene_tabs(); + return idx; +} + Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported) { if (!is_inside_tree()) { @@ -4792,8 +4800,7 @@ void EditorNode::remove_control_from_dock(Control *p_control) { } } - ERR_EXPLAIN("Control was not in dock"); - ERR_FAIL_COND(!dock); + ERR_FAIL_COND_MSG(!dock, "Control was not in dock."); dock->remove_child(p_control); _update_dock_slots_visibility(); @@ -5505,6 +5512,9 @@ EditorNode::EditorNode() { } } + // Define a minimum window size to prevent UI elements from overlapping or being cut off + OS::get_singleton()->set_min_window_size(Size2(1024, 600) * EDSCALE); + ResourceLoader::set_abort_on_missing_resources(false); FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); diff --git a/editor/editor_node.h b/editor/editor_node.h index 10ad2d691e..a8443549ed 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -745,6 +745,7 @@ public: void fix_dependencies(const String &p_for_file); void clear_scene() { _cleanup_scene(); } + int new_scene(); Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false); Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false); diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 327e61cea3..4a7a9fb863 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -46,8 +46,7 @@ bool EditorResourcePreviewGenerator::handles(const String &p_type) const { if (get_script_instance() && get_script_instance()->has_method("handles")) { return get_script_instance()->call("handles", p_type); } - ERR_EXPLAIN("EditorResourcePreviewGenerator::handles needs to be overridden"); - ERR_FAIL_V(false); + ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::handles needs to be overridden."); } Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 &p_size) const { @@ -55,8 +54,7 @@ Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const S if (get_script_instance() && get_script_instance()->has_method("generate")) { return get_script_instance()->call("generate", p_from, p_size); } - ERR_EXPLAIN("EditorResourcePreviewGenerator::generate needs to be overridden"); - ERR_FAIL_V(Ref<Texture>()); + ERR_FAIL_V_MSG(Ref<Texture>(), "EditorResourcePreviewGenerator::generate needs to be overridden."); } Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 &p_size) const { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 2d2e53370d..cb3bfa3a49 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -334,9 +334,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/dim_editor_on_dialog_popup", true); _initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS - hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT); + hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS - hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT); + hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); _initial_set("interface/editor/hide_console_window", false); @@ -1451,10 +1451,7 @@ void EditorSettings::add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcu bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const { const Map<String, Ref<ShortCut> >::Element *E = shortcuts.find(p_name); - if (!E) { - ERR_EXPLAIN("Unknown Shortcut: " + p_name); - ERR_FAIL_V(false); - } + ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_name + "."); return E->get()->is_shortcut(p_event); } @@ -1483,10 +1480,8 @@ Ref<ShortCut> ED_GET_SHORTCUT(const String &p_path) { } Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(p_path); - if (!sc.is_valid()) { - ERR_EXPLAIN("Used ED_GET_SHORTCUT with invalid shortcut: " + p_path); - ERR_FAIL_COND_V(!sc.is_valid(), sc); - } + + ERR_FAIL_COND_V_MSG(!sc.is_valid(), sc, "Used ED_GET_SHORTCUT with invalid shortcut: " + p_path + "."); return sc; } diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 379b8a2980..46a30b7554 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -47,42 +47,48 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) { return; Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid()) { - if (mb->is_pressed()) { + if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->is_pressed()) { - if (updown_offset != -1 && mb->get_position().x > updown_offset) { - //there is an updown, so use it. - if (mb->get_position().y < get_size().height / 2) { - set_value(get_value() + get_step()); + if (updown_offset != -1 && mb->get_position().x > updown_offset) { + //there is an updown, so use it. + if (mb->get_position().y < get_size().height / 2) { + set_value(get_value() + get_step()); + } else { + set_value(get_value() - get_step()); + } + return; } else { - set_value(get_value() - get_step()); + + grabbing_spinner_attempt = true; + grabbing_spinner_dist_cache = 0; + pre_grab_value = get_value(); + grabbing_spinner = false; + grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position(); } - return; } else { - grabbing_spinner_attempt = true; - grabbing_spinner_dist_cache = 0; - pre_grab_value = get_value(); - grabbing_spinner = false; - grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position(); - } - } else { + if (grabbing_spinner_attempt) { - if (grabbing_spinner_attempt) { + if (grabbing_spinner) { - if (grabbing_spinner) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos); + update(); + } else { + _focus_entered(); + } - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); - Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos); - update(); - } else { - _focus_entered(); + grabbing_spinner = false; + grabbing_spinner_attempt = false; } - - grabbing_spinner = false; - grabbing_spinner_attempt = false; } + } else if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN) { + + if (grabber->is_visible()) + call_deferred("update"); } } diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 97af0d08ea..d962001b38 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -351,6 +351,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("dark_color_3", "Editor", dark_color_3); theme->set_color("contrast_color_1", "Editor", contrast_color_1); theme->set_color("contrast_color_2", "Editor", contrast_color_2); + theme->set_color("box_selection_fill_color", "Editor", accent_color * Color(1, 1, 1, 0.3)); + theme->set_color("box_selection_stroke_color", "Editor", accent_color * Color(1, 1, 1, 0.8)); theme->set_color("font_color", "Editor", font_color); theme->set_color("highlighted_font_color", "Editor", font_color_hl); @@ -1064,6 +1066,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // FileDialog theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons")); + // Use a different color for folder icons to make them easier to distinguish from files. + // On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color. + theme->set_color("folder", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(5, 5, 5)).linear_interpolate(accent_color, 0.7)); theme->set_color("files_disabled", "FileDialog", font_color_disabled); // color picker diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 72a4b43737..68e859966c 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -321,8 +321,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (!f) { ret = unzGoToNextFile(pkg); fc++; - ERR_EXPLAIN("Can't open file from path: " + String(to_write)); - ERR_CONTINUE(true); + ERR_CONTINUE_MSG(true, "Can't open file from path: " + String(to_write) + "."); } f->store_buffer(data.ptr(), data.size()); @@ -591,8 +590,7 @@ Error ExportTemplateManager::install_android_template() { zlib_filefunc_def io = zipio_create_io_from_file(&src_f); unzFile pkg = unzOpen2(source_zip.utf8().get_data(), &io); - ERR_EXPLAIN("Android sources not in zip format"); - ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in zip format."); int ret = unzGoToFirstFile(pkg); diff --git a/editor/file_type_cache.cpp b/editor/file_type_cache.cpp index 1bcbc45d3b..746d38f2b5 100644 --- a/editor/file_type_cache.cpp +++ b/editor/file_type_cache.cpp @@ -83,11 +83,8 @@ void FileTypeCache::save() { GLOBAL_LOCK_FUNCTION String project = ProjectSettings::get_singleton()->get_resource_path(); FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::WRITE); - if (!f) { - ERR_EXPLAIN(TTR("Can't open file_type_cache.cch for writing, not saving file type cache!")); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!f, "Can't open file_type_cache.cch for writing, not saving file type cache!"); const String *K = NULL; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 8e332ad20e..83904800e9 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -39,6 +39,7 @@ #include "editor_node.h" #include "editor_settings.h" #include "scene/main/viewport.h" +#include "scene/resources/packed_scene.h" Ref<Texture> FileSystemDock::_get_tree_item_icon(EditorFileSystemDirectory *p_dir, int p_idx) { Ref<Texture> file_icon; @@ -63,6 +64,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_text(0, dname); subdirectory_item->set_icon(0, get_icon("Folder", "EditorIcons")); + subdirectory_item->set_icon_color(0, get_color("folder", "FileDialog")); subdirectory_item->set_selectable(0, true); String lpath = p_dir->get_path(); subdirectory_item->set_metadata(0, lpath); @@ -185,15 +187,19 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo continue; Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons"); + const Color folder_color = get_color("folder", "FileDialog"); String text; Ref<Texture> icon; + Color color; if (fave == "res://") { text = "/"; icon = folder_icon; + color = folder_color; } else if (fave.ends_with("/")) { text = fave.substr(0, fave.length() - 1).get_file(); icon = folder_icon; + color = folder_color; } else { text = fave.get_file(); int index; @@ -203,12 +209,14 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo } else { icon = get_icon("File", "EditorIcons"); } + color = Color(1, 1, 1); } if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) { TreeItem *ti = tree->create_item(favorites); ti->set_text(0, text); ti->set_icon(0, icon); + ti->set_icon_color(0, color); ti->set_tooltip(0, fave); ti->set_selectable(0, true); ti->set_metadata(0, fave); @@ -452,8 +460,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa path = target_path + "/"; } else { memdelete(dirAccess); - ERR_EXPLAIN(vformat(TTR("Cannot navigate to '%s' as it has not been found in the file system!"), p_path)); - ERR_FAIL(); + ERR_FAIL_MSG(vformat("Cannot navigate to '%s' as it has not been found in the file system!", p_path)); } memdelete(dirAccess); } @@ -639,6 +646,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { } Ref<Texture> folder_icon = (use_thumbnails) ? folder_thumbnail : get_icon("folder", "FileDialog"); + const Color folder_color = get_color("folder", "FileDialog"); // Build the FileInfo list List<FileInfo> filelist; @@ -716,6 +724,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { files->set_item_metadata(files->get_item_count() - 1, bd); files->set_item_selectable(files->get_item_count() - 1, false); + files->set_item_icon_modulate(files->get_item_count() - 1, folder_color); } for (int i = 0; i < efd->get_subdir_count(); i++) { @@ -724,6 +733,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { files->add_item(dname, folder_icon, true); files->set_item_metadata(files->get_item_count() - 1, directory.plus_file(dname) + "/"); + files->set_item_icon_modulate(files->get_item_count() - 1, folder_color); if (cselection.has(dname)) { files->select(files->get_item_count() - 1, false); @@ -1250,6 +1260,48 @@ void FileSystemDock::_make_dir_confirm() { } } +void FileSystemDock::_make_scene_confirm() { + String scene_name = make_scene_dialog_text->get_text().strip_edges(); + + if (scene_name.length() == 0) { + EditorNode::get_singleton()->show_warning(TTR("No name provided.")); + return; + } + + String directory = path; + if (!directory.ends_with("/")) { + directory = directory.get_base_dir(); + } + + String extension = scene_name.get_extension(); + List<String> extensions; + Ref<PackedScene> sd = memnew(PackedScene); + ResourceSaver::get_recognized_extensions(sd, &extensions); + + bool extension_correct = false; + for (List<String>::Element *E = extensions.front(); E; E = E->next()) { + if (E->get() == extension) { + extension_correct = true; + break; + } + } + if (!extension_correct) + scene_name = scene_name.get_basename() + ".tscn"; + + scene_name = directory.plus_file(scene_name); + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->file_exists(scene_name)) { + EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); + memdelete(da); + return; + } + memdelete(da); + + int idx = editor->new_scene(); + editor->get_editor_data().set_scene_path(idx, scene_name); +} + void FileSystemDock::_file_deleted(String p_file) { emit_signal("file_deleted", p_file); } @@ -1698,6 +1750,13 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected make_dir_dialog_text->grab_focus(); } break; + case FILE_NEW_SCENE: { + make_scene_dialog_text->set_text("new scene"); + make_scene_dialog_text->select_all(); + make_scene_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE); + make_scene_dialog_text->grab_focus(); + } break; + case FILE_NEW_SCRIPT: { // Create a new script String fpath = path; @@ -2157,6 +2216,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str p_popup->add_separator(); if (p_display_path_dependent_options) { p_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + p_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE); p_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); p_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); } @@ -2195,6 +2255,7 @@ void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) { tree_popup->clear(); tree_popup->set_size(Size2(1, 1)); tree_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + tree_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE); tree_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); tree_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); tree_popup->set_position(tree->get_global_position() + p_pos); @@ -2237,6 +2298,7 @@ void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) { file_list_popup->set_size(Size2(1, 1)); file_list_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + file_list_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE); file_list_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); file_list_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); file_list_popup->add_item(TTR("Show in File Manager"), FILE_SHOW_IN_EXPLORER); @@ -2411,6 +2473,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_fs_changed"), &FileSystemDock::_fs_changed); ClassDB::bind_method(D_METHOD("_tree_multi_selected"), &FileSystemDock::_tree_multi_selected); ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); + ClassDB::bind_method(D_METHOD("_make_scene_confirm"), &FileSystemDock::_make_scene_confirm); ClassDB::bind_method(D_METHOD("_resource_created"), &FileSystemDock::_resource_created); ClassDB::bind_method(D_METHOD("_move_operation_confirm", "to_path", "overwrite"), &FileSystemDock::_move_operation_confirm, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite); @@ -2626,6 +2689,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { make_dir_dialog->register_text_enter(make_dir_dialog_text); make_dir_dialog->connect("confirmed", this, "_make_dir_confirm"); + make_scene_dialog = memnew(ConfirmationDialog); + make_scene_dialog->set_title(TTR("Create Scene")); + VBoxContainer *make_scene_dialog_vb = memnew(VBoxContainer); + make_scene_dialog->add_child(make_scene_dialog_vb); + + make_scene_dialog_text = memnew(LineEdit); + make_scene_dialog_vb->add_margin_child(TTR("Name:"), make_scene_dialog_text); + add_child(make_scene_dialog); + make_scene_dialog->register_text_enter(make_scene_dialog_text); + make_scene_dialog->connect("confirmed", this, "_make_scene_confirm"); + make_script_dialog_text = memnew(ScriptCreateDialog); make_script_dialog_text->set_title(TTR("Create Script")); add_child(make_script_dialog_text); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 6de370ad29..cc5ba94b48 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -87,6 +87,7 @@ private: FILE_INFO, FILE_NEW_FOLDER, FILE_NEW_SCRIPT, + FILE_NEW_SCENE, FILE_SHOW_IN_EXPLORER, FILE_COPY_PATH, FILE_NEW_RESOURCE, @@ -135,6 +136,8 @@ private: LineEdit *duplicate_dialog_text; ConfirmationDialog *make_dir_dialog; LineEdit *make_dir_dialog_text; + ConfirmationDialog *make_scene_dialog; + LineEdit *make_scene_dialog_text; ConfirmationDialog *overwrite_dialog; ScriptCreateDialog *make_script_dialog_text; CreateDialog *new_resource_dialog; @@ -213,6 +216,7 @@ private: void _resource_created() const; void _make_dir_confirm(); + void _make_scene_confirm(); void _rename_operation_confirm(); void _duplicate_operation_confirm(); void _move_with_overwrite(); diff --git a/editor/icons/icon_editor_curve_handle.svg b/editor/icons/icon_editor_curve_handle.svg new file mode 100644 index 0000000000..c405ceab9d --- /dev/null +++ b/editor/icons/icon_editor_curve_handle.svg @@ -0,0 +1 @@ +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill="#fefefe" r="2.75" stroke="#000" stroke-linecap="square"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_editor_path_sharp_handle.svg b/editor/icons/icon_editor_path_sharp_handle.svg new file mode 100644 index 0000000000..db160dfeae --- /dev/null +++ b/editor/icons/icon_editor_path_sharp_handle.svg @@ -0,0 +1 @@ +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m-3.035534-10.106602h6.071068v6.071068h-6.071068z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="matrix(-.70710678 .70710678 -.70710678 -.70710678 0 0)"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_editor_path_smooth_handle.svg b/editor/icons/icon_editor_path_smooth_handle.svg new file mode 100644 index 0000000000..34f3d290bd --- /dev/null +++ b/editor/icons/icon_editor_path_smooth_handle.svg @@ -0,0 +1 @@ +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m1.5-8.5h7v7h-7z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="rotate(90)"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_timeline_indicator.svg b/editor/icons/icon_timeline_indicator.svg new file mode 100644 index 0000000000..fd18192705 --- /dev/null +++ b/editor/icons/icon_timeline_indicator.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 0h10l-4 4h-2z" fill="#fefefe"/></svg>
\ No newline at end of file diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 1c4a8c43a9..449124acec 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -692,16 +692,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me pre_weights[w_i] = weights; - /* - for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) { - - int dst = E->get(); - ERR_EXPLAIN("invalid vertex index in array"); - ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA); - vertex_array[dst].weights=weights; - - }*/ - index_ofs += wstride * amount; } @@ -711,7 +701,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me Set<Collada::Vertex> vertex_set; //vertex set will be the vertices List<int> indices_list; //indices will be the indices - //Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph) /**************************/ /* CREATE PRIMITIVE ARRAY */ @@ -834,9 +823,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me vertex_set.insert(vertex); } - /* if (!vertex_map.has(vertex_index)) - vertex_map[vertex_index]=Set<int>(); - vertex_map[vertex_index].insert(index); //should be outside..*/ //build triangles if needed if (j == 0) prev2[0] = index; @@ -1204,10 +1190,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } } - if (ngsource != "") { - ERR_EXPLAIN("Controller Instance Source '" + ngsource + "' is neither skin or morph!"); - ERR_FAIL_V(ERR_INVALID_DATA); - } + ERR_FAIL_COND_V_MSG(ngsource != "", ERR_INVALID_DATA, "Controller instance source '" + ngsource + "' is neither skin or morph!"); } else { meshid = ng2->source; @@ -1608,7 +1591,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } if (xform_idx == -1) { - WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param); + WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param + "."); continue; } @@ -1630,8 +1613,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } else if (data.size() == xf.data.size()) { xf.data = data; } else { - ERR_EXPLAIN("Component " + at.component + " has datasize " + itos(data.size()) + ", xfdatasize " + itos(xf.data.size())); - ERR_CONTINUE(data.size() != xf.data.size()); + ERR_CONTINUE_MSG(data.size() != xf.data.size(), "Component " + at.component + " has datasize " + itos(data.size()) + ", xfdatasize " + itos(xf.data.size()) + "."); } } diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index c9c5b3818f..84dd1aa866 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1544,8 +1544,7 @@ Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) { camera.fov_size = 10; } } else { - ERR_EXPLAIN("Camera should be in 'orthographic' or 'perspective'"); - ERR_FAIL_V(ERR_PARSE_ERROR); + ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera should be in 'orthographic' or 'perspective'"); } state.cameras.push_back(camera); diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index cfcdbc8de4..301422a25a 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -101,8 +101,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const for (int i = 1; i < line.size(); i++) { String locale = line[i]; - ERR_EXPLAIN("Error importing CSV translation: '" + locale + "' is not a valid locale"); - ERR_FAIL_COND_V(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR); + ERR_FAIL_COND_V_MSG(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR, "Error importing CSV translation: '" + locale + "' is not a valid locale."); locales.push_back(locale); Ref<Translation> translation; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 868f67fd77..9061c92f6e 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -45,8 +45,7 @@ uint32_t EditorOBJImporter::get_import_flags() const { static Error _parse_material_library(const String &p_path, Map<String, Ref<SpatialMaterial> > &material_map, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_EXPLAIN(vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); Ref<SpatialMaterial> current; String current_name; @@ -207,8 +206,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_EXPLAIN(vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); Ref<ArrayMesh> mesh; mesh.instance(); diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index d267b29224..4fd4ab2f2e 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -123,8 +123,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->close(); memdelete(file); - ERR_EXPLAIN("Not a WAV file (no WAVE RIFF Header)"); - ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header)."); } int format_bits = 0; @@ -166,16 +165,14 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s if (compression_code != 1 && compression_code != 3) { file->close(); memdelete(file); - ERR_EXPLAIN("Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); } format_channels = file->get_16(); if (format_channels != 1 && format_channels != 2) { file->close(); memdelete(file); - ERR_EXPLAIN("Format not supported for WAVE file (not stereo or mono)."); - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not stereo or mono)."); } format_freq = file->get_32(); //sampling rate @@ -187,8 +184,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s if (format_bits % 8 || format_bits == 0) { file->close(); memdelete(file); - ERR_EXPLAIN("Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32)."); - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32)."); } /* Don't need anything else, continue */ @@ -258,8 +254,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s if (file->eof_reached()) { file->close(); memdelete(file); - ERR_EXPLAIN("Premature end of file."); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Premature end of file."); } } diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp index 1c0151ed0a..d6df3bd369 100644 --- a/editor/node_dock.cpp +++ b/editor/node_dock.cpp @@ -56,10 +56,7 @@ void NodeDock::_bind_methods() { void NodeDock::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - connections_button->set_icon(get_icon("Signals", "EditorIcons")); - groups_button->set_icon(get_icon("Groups", "EditorIcons")); - } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { connections_button->set_icon(get_icon("Signals", "EditorIcons")); groups_button->set_icon(get_icon("Groups", "EditorIcons")); } @@ -131,7 +128,7 @@ NodeDock::NodeDock() { groups->hide(); select_a_node = memnew(Label); - select_a_node->set_text(TTR("Select a Node to edit Signals and Groups.")); + select_a_node->set_text(TTR("Select a single node to edit its signals and groups.")); select_a_node->set_v_size_flags(SIZE_EXPAND_FILL); select_a_node->set_valign(Label::VALIGN_CENTER); select_a_node->set_align(Label::ALIGN_CENTER); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 574b47d770..7f023af848 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -571,7 +571,8 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl return; Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); - const Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); + // All polygon points are sharp, so use the sharp handle icon + const Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons"); const Vertex active_point = get_active_point(); const int n_polygons = _get_polygon_count(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 98c2f21e45..cc707dbf44 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2918,10 +2918,15 @@ void CanvasItemEditor::_draw_selection() { Point2 bsfrom = transform.xform(drag_from); Point2 bsto = transform.xform(box_selecting_to); - VisualServer::get_singleton()->canvas_item_add_rect( - ci, + viewport->draw_rect( Rect2(bsfrom, bsto - bsfrom), - get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); + get_color("box_selection_fill_color", "Editor")); + + viewport->draw_rect( + Rect2(bsfrom, bsto - bsfrom), + get_color("box_selection_stroke_color", "Editor"), + false, + Math::round(EDSCALE)); } if (drag_type == DRAG_ROTATE) { diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 7c2116f06b..9d625af959 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -87,8 +87,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { Ref<Image> img; img.instance(); Error err = ImageLoader::load_image(source_emission_file, img); - ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Error loading image: " + source_emission_file + "."); if (img->is_compressed()) { img->decompress(); @@ -196,8 +195,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { valid_normals.resize(vpc); } - ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); - ERR_FAIL_COND(valid_positions.size() == 0); + ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image..."); if (capture_colors) { PoolColorArray pca; diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index d59efe49e7..3ea014a38d 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -147,9 +147,8 @@ void MultiMeshEditor::_populate() { w.release(); PoolVector<Face3> faces = geometry; - ERR_EXPLAIN(TTR("Parent has no solid faces to populate.")); int facecount = faces.size(); - ERR_FAIL_COND(!facecount); + ERR_FAIL_COND_MSG(!facecount, "Parent has no solid faces to populate."); PoolVector<Face3>::Read r = faces.read(); @@ -164,10 +163,8 @@ void MultiMeshEditor::_populate() { area_accum += area; } - ERR_EXPLAIN(TTR("Couldn't map area.")); - ERR_FAIL_COND(triangle_area_map.size() == 0); - ERR_EXPLAIN(TTR("Couldn't map area.")); - ERR_FAIL_COND(area_accum == 0); + ERR_FAIL_COND_MSG(triangle_area_map.size() == 0, "Couldn't map area."); + ERR_FAIL_COND_MSG(area_accum == 0, "Couldn't map area."); Ref<MultiMesh> multimesh = memnew(MultiMesh); multimesh->set_mesh(mesh); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index e68bca55cb..8025e12885 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -160,8 +160,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { Ref<Image> img; img.instance(); Error err = ImageLoader::load_image(source_emission_file, img); - ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Error loading image: " + source_emission_file + "."); if (img->is_compressed()) { img->decompress(); @@ -269,8 +268,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { valid_normals.resize(vpc); } - ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); - ERR_FAIL_COND(valid_positions.size() == 0); + ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image..."); PoolVector<uint8_t> texdata; diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index b87bd29cbd..f02dc0bd6d 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -367,18 +367,18 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - if (!node) + if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid()) return; - if (!node->is_visible_in_tree()) - return; + Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - if (!node->get_curve().is_valid()) - return; + const Ref<Texture> path_sharp_handle = get_icon("EditorPathSharpHandle", "EditorIcons"); + const Ref<Texture> path_smooth_handle = get_icon("EditorPathSmoothHandle", "EditorIcons"); + // Both handle icons must be of the same size + const Size2 handle_size = path_sharp_handle->get_size(); - Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); - Size2 handle_size = handle->get_size(); + const Ref<Texture> curve_handle = get_icon("EditorCurveHandle", "EditorIcons"); + const Size2 curve_handle_size = curve_handle->get_size(); Ref<Curve2D> curve = node->get_curve(); @@ -387,19 +387,35 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { for (int i = 0; i < len; i++) { Vector2 point = xform.xform(curve->get_point_position(i)); - vpc->draw_texture_rect(handle, Rect2(point - handle_size * 0.5, handle_size), false, Color(1, 1, 1, 1)); + // Determines the point icon to be used + bool smooth = false; if (i < len - 1) { Vector2 pointout = xform.xform(curve->get_point_position(i) + curve->get_point_out(i)); - vpc->draw_line(point, pointout, Color(0.5, 0.5, 1.0, 0.8), 1.0); - vpc->draw_texture_rect(handle, Rect2(pointout - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3)); + if (point != pointout) { + smooth = true; + // Draw the line with a dark and light color to be visible on all backgrounds + vpc->draw_line(point, pointout, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true); + vpc->draw_line(point, pointout, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true); + vpc->draw_texture_rect(curve_handle, Rect2(pointout - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75)); + } } if (i > 0) { Vector2 pointin = xform.xform(curve->get_point_position(i) + curve->get_point_in(i)); - vpc->draw_line(point, pointin, Color(0.5, 0.5, 1.0, 0.8), 1.0); - vpc->draw_texture_rect(handle, Rect2(pointin - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3)); + if (point != pointin) { + smooth = true; + // Draw the line with a dark and light color to be visible on all backgrounds + vpc->draw_line(point, pointin, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true); + vpc->draw_line(point, pointin, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true); + vpc->draw_texture_rect(curve_handle, Rect2(pointin - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75)); + } } + + vpc->draw_texture_rect( + smooth ? path_smooth_handle : path_sharp_handle, + Rect2(point - handle_size * 0.5, handle_size), + false); } if (on_edge) { diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 1ae5acc5ff..2493380585 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -652,7 +652,6 @@ PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() { Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); create_material("path_material", path_color); - path_color.a = 0.4; - create_material("path_thin_material", path_color); + create_material("path_thin_material", Color(0.5, 0.5, 0.5)); create_handle_material("handles"); } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 59004a08c0..bd532a6418 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -1045,8 +1045,8 @@ void Polygon2DEditor::_uv_draw() { } } - Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); - Ref<Texture> internal_handle = get_icon("EditorInternalHandle", "EditorIcons"); + // All UV points are sharp, so use the sharp handle icon + Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons"); Color poly_line_color = Color(0.9, 0.5, 0.5); if (polygons.size() || polygon_create.size()) { @@ -1120,7 +1120,8 @@ void Polygon2DEditor::_uv_draw() { if (i < uv_draw_max) { uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5); } else { - uv_edit_draw->draw_texture(internal_handle, mtx.xform(uvs[i]) - internal_handle->get_size() * 0.5); + // Internal vertex + uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5, Color(0.6, 0.8, 1)); } } } diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index f2b1aad59d..2eb3ce1ec3 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2373,16 +2373,22 @@ void SpatialEditorViewport::_draw() { get_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r); } - RID ci = surface->get_canvas_item(); - if (cursor.region_select) { + const Rect2 selection_rect = Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin); - VisualServer::get_singleton()->canvas_item_add_rect( - ci, - Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin), - get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); + surface->draw_rect( + selection_rect, + get_color("box_selection_fill_color", "Editor")); + + surface->draw_rect( + selection_rect, + get_color("box_selection_stroke_color", "Editor"), + false, + Math::round(EDSCALE)); } + RID ci = surface->get_canvas_item(); + if (message_time > 0) { Ref<Font> font = get_font("font", "Label"); Point2 msgpos = Point2(5, get_size().y - 20); @@ -5170,7 +5176,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { // We add a bit of margin to the from position to avoid it from snapping // when the spatial is already on a floor and there's another floor under // it - from = from + Vector3(0.0, 0.1, 0.0); + from = from + Vector3(0.0, 0.2, 0.0); Dictionary d; @@ -5185,31 +5191,56 @@ void SpatialEditor::snap_selected_nodes_to_floor() { Array keys = snap_data.keys(); - if (keys.size()) { - undo_redo->create_action(TTR("Snap Nodes To Floor")); + // The maximum height an object can travel to be snapped + const float max_snap_height = 20.0; + + // Will be set to `true` if at least one node from the selection was sucessfully snapped + bool snapped_to_floor = false; + if (keys.size()) { + // For snapping to be performed, there must be solid geometry under at least one of the selected nodes. + // We need to check this before snapping to register the undo/redo action only if needed. for (int i = 0; i < keys.size(); i++) { Node *node = keys[i]; Spatial *sp = Object::cast_to<Spatial>(node); - Dictionary d = snap_data[node]; Vector3 from = d["from"]; - Vector3 position_offset = d["position_offset"]; - - Vector3 to = from - Vector3(0.0, 10.0, 0.0); + Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); Set<RID> excluded = _get_physics_bodies_rid(sp); if (ss->intersect_ray(from, to, result, excluded)) { - Transform new_transform = sp->get_global_transform(); - new_transform.origin.y = result.position.y; - new_transform.origin = new_transform.origin - position_offset; - - undo_redo->add_do_method(sp, "set_global_transform", new_transform); - undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform()); + snapped_to_floor = true; } } - undo_redo->commit_action(); + if (snapped_to_floor) { + undo_redo->create_action(TTR("Snap Nodes To Floor")); + + // Perform snapping if at least one node can be snapped + for (int i = 0; i < keys.size(); i++) { + Node *node = keys[i]; + Spatial *sp = Object::cast_to<Spatial>(node); + Dictionary d = snap_data[node]; + Vector3 from = d["from"]; + Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); + Set<RID> excluded = _get_physics_bodies_rid(sp); + + if (ss->intersect_ray(from, to, result, excluded)) { + Vector3 position_offset = d["position_offset"]; + Transform new_transform = sp->get_global_transform(); + + new_transform.origin.y = result.position.y; + new_transform.origin = new_transform.origin - position_offset; + + undo_redo->add_do_method(sp, "set_global_transform", new_transform); + undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform()); + } + } + + undo_redo->commit_action(); + } else { + EditorNode::get_singleton()->show_warning(TTR("Couldn't find a solid floor to snap the selection to.")); + } } } @@ -5219,42 +5250,6 @@ void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) { return; snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL); - - Ref<InputEventKey> k = p_event; - - if (k.is_valid()) { - - // Note: need to check is_echo because first person movement keys might still be held - if (!is_any_freelook_active() && !p_event->is_echo()) { - - if (!k->is_pressed()) - return; - - if (ED_IS_SHORTCUT("spatial_editor/tool_select", p_event)) { - _menu_item_pressed(MENU_TOOL_SELECT); - } else if (ED_IS_SHORTCUT("spatial_editor/tool_move", p_event)) { - _menu_item_pressed(MENU_TOOL_MOVE); - } else if (ED_IS_SHORTCUT("spatial_editor/tool_rotate", p_event)) { - _menu_item_pressed(MENU_TOOL_ROTATE); - } else if (ED_IS_SHORTCUT("spatial_editor/tool_scale", p_event)) { - _menu_item_pressed(MENU_TOOL_SCALE); - } else if (ED_IS_SHORTCUT("spatial_editor/snap_to_floor", p_event)) { - snap_selected_nodes_to_floor(); - } else if (ED_IS_SHORTCUT("spatial_editor/local_coords", p_event)) { - if (are_local_coords_enabled()) { - _menu_item_toggled(false, MENU_TOOL_LOCAL_COORDS); - } else { - _menu_item_toggled(true, MENU_TOOL_LOCAL_COORDS); - } - } else if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) { - if (is_snap_enabled()) { - _menu_item_toggled(false, MENU_TOOL_USE_SNAP); - } else { - _menu_item_toggled(true, MENU_TOOL_USE_SNAP); - } - } - } - } } void SpatialEditor::_notification(int p_what) { @@ -5528,7 +5523,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_SELECT]->set_pressed(true); button_binds.write[0] = MENU_TOOL_SELECT; tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_SELECT]->set_tooltip(TTR("Select Mode (Q)") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection")); + tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q)); + tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection")); hbc_menu->add_child(memnew(VSeparator)); @@ -5538,7 +5534,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_MOVE]->set_flat(true); button_binds.write[0] = MENU_TOOL_MOVE; tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_MOVE]->set_tooltip(TTR("Move Mode (W)")); + tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W)); tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton); hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]); @@ -5546,7 +5542,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_ROTATE]->set_flat(true); button_binds.write[0] = MENU_TOOL_ROTATE; tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_ROTATE]->set_tooltip(TTR("Rotate Mode (E)")); + tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E)); tool_button[TOOL_MODE_SCALE] = memnew(ToolButton); hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]); @@ -5554,7 +5550,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_SCALE]->set_flat(true); button_binds.write[0] = MENU_TOOL_SCALE; tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)")); + tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R)); hbc_menu->add_child(memnew(VSeparator)); @@ -5598,9 +5594,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true); button_binds.write[0] = MENU_TOOL_LOCAL_COORDS; tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", this, "_menu_item_toggled", button_binds); - ED_SHORTCUT("spatial_editor/local_coords", TTR("Local Coords"), KEY_T); - sct = ED_GET_SHORTCUT("spatial_editor/local_coords").ptr()->get_as_text(); - tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_tooltip(vformat(TTR("Local Space Mode (%s)"), sct)); + tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T)); tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton); hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]); @@ -5608,9 +5602,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true); button_binds.write[0] = MENU_TOOL_USE_SNAP; tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds); - ED_SHORTCUT("spatial_editor/snap", TTR("Snap"), KEY_Y); - sct = ED_GET_SHORTCUT("spatial_editor/snap").ptr()->get_as_text(); - tool_option_button[TOOL_OPT_USE_SNAP]->set_tooltip(vformat(TTR("Snap Mode (%s)"), sct)); + tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y)); hbc_menu->add_child(memnew(VSeparator)); @@ -5630,12 +5622,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F); ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M); ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F); - - ED_SHORTCUT("spatial_editor/tool_select", TTR("Tool Select"), KEY_Q); - ED_SHORTCUT("spatial_editor/tool_move", TTR("Tool Move"), KEY_W); - ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Tool Rotate"), KEY_E); - ED_SHORTCUT("spatial_editor/tool_scale", TTR("Tool Scale"), KEY_R); - ED_SHORTCUT("spatial_editor/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F); PopupMenu *p; diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 56357f298a..3055a9382c 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -191,11 +191,9 @@ void ThemeEditor::_save_template_cbk(String fname) { } FileAccess *file = FileAccess::open(filename, FileAccess::WRITE); - if (!file) { - ERR_EXPLAIN(TTR("Can't save theme to file:") + " " + filename); - return; - } + ERR_FAIL_COND_MSG(!file, "Can't save theme to file: " + filename + "."); + file->store_line("; ******************* "); file->store_line("; Template Theme File "); file->store_line("; ******************* "); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index b2f06ca41f..b4cce9745e 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -2006,7 +2006,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { // Tools paint_button = memnew(ToolButton); paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P)); - paint_button->set_tooltip(TTR("Shift+RMB: Line Draw\nShift+Ctrl+RMB: Rectangle Paint")); + paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint")); paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE)); paint_button->set_toggle_mode(true); toolbar->add_child(paint_button); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 1a27e749e2..c1e85788f8 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -646,8 +646,7 @@ void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { for (int i = 0; i < p_paths.size(); i++) { Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i])); - ERR_EXPLAIN("'" + p_paths[i] + "' is not a valid texture."); - ERR_CONTINUE(!t.is_valid()); + ERR_CONTINUE_MSG(!t.is_valid(), "'" + p_paths[i] + "' is not a valid texture."); if (texture_map.has(t->get_rid())) { invalid_count++; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index e193e237de..589964f620 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -69,8 +69,16 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } visual_shader = Ref<VisualShader>(p_visual_shader); + if (!visual_shader->is_connected("changed", this, "_update_preview")) { + visual_shader->connect("changed", this, "_update_preview"); + } visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE); } else { + if (visual_shader.is_valid()) { + if (visual_shader->is_connected("changed", this, "")) { + visual_shader->disconnect("changed", this, "_update_preview"); + } + } visual_shader.unref(); } @@ -81,6 +89,7 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { _clear_buffer(); _update_custom_nodes(); _update_options_menu(); + _update_preview(); } _update_graph(); } @@ -524,21 +533,23 @@ void VisualShaderEditor::_update_graph() { offset->set_custom_minimum_size(Size2(0, 6 * EDSCALE)); node->add_child(offset); - HBoxContainer *hb2 = memnew(HBoxContainer); + if (group_node->is_editable()) { + HBoxContainer *hb2 = memnew(HBoxContainer); - Button *add_input_btn = memnew(Button); - add_input_btn->set_text(TTR("Add input +")); - add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED); - hb2->add_child(add_input_btn); + Button *add_input_btn = memnew(Button); + add_input_btn->set_text(TTR("Add input +")); + add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED); + hb2->add_child(add_input_btn); - hb2->add_spacer(); + hb2->add_spacer(); - Button *add_output_btn = memnew(Button); - add_output_btn->set_text(TTR("Add output +")); - add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED); - hb2->add_child(add_output_btn); + Button *add_output_btn = memnew(Button); + add_output_btn->set_text(TTR("Add output +")); + add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED); + hb2->add_child(add_output_btn); - node->add_child(hb2); + node->add_child(hb2); + } } for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { @@ -1566,6 +1577,29 @@ void VisualShaderEditor::_notification(int p_what) { node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons")); + preview_shader->set_icon(Control::get_icon("Shader", "EditorIcons")); + + { + Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); + Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); + Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + + preview_text->add_color_override("background_color", background_color); + + for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { + + preview_text->add_keyword_color(E->get(), keyword_color); + } + + preview_text->add_font_override("font", get_font("expression", "EditorFonts")); + preview_text->add_color_override("font_color", text_color); + preview_text->add_color_override("symbol_color", symbol_color); + preview_text->add_color_region("/*", "*/", comment_color, false); + preview_text->add_color_region("//", "", comment_color, false); + } + tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons")); if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) @@ -2016,6 +2050,15 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } } +void VisualShaderEditor::_show_preview_text() { + preview_showed = !preview_showed; + preview_text->set_visible(preview_showed); +} + +void VisualShaderEditor::_update_preview() { + preview_text->set_text(visual_shader->get_code()); +} + void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_rebuild", &VisualShaderEditor::_rebuild); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); @@ -2055,6 +2098,8 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_node_resized", &VisualShaderEditor::_node_resized); ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size); ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer); + ClassDB::bind_method("_show_preview_text", &VisualShaderEditor::_show_preview_text); + ClassDB::bind_method("_update_preview", &VisualShaderEditor::_update_preview); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); @@ -2081,13 +2126,23 @@ VisualShaderEditor::VisualShaderEditor() { saved_node_pos = Point2(0, 0); ShaderLanguage::get_keyword_list(&keyword_list); + preview_showed = false; + to_node = -1; to_slot = -1; from_node = -1; from_slot = -1; + main_box = memnew(HSplitContainer); + main_box->set_v_size_flags(SIZE_EXPAND_FILL); + main_box->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(main_box); + graph = memnew(GraphEdit); - add_child(graph); + graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL); + graph->set_v_size_flags(SIZE_EXPAND_FILL); + graph->set_h_size_flags(SIZE_EXPAND_FILL); + main_box->add_child(graph); graph->set_drag_forwarding(this); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN); @@ -2136,6 +2191,25 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->move_child(add_node, 0); add_node->connect("pressed", this, "_show_members_dialog", varray(false)); + preview_shader = memnew(ToolButton); + preview_shader->set_toggle_mode(true); + preview_shader->set_tooltip(TTR("Show resulted shader code.")); + graph->get_zoom_hbox()->add_child(preview_shader); + preview_shader->connect("pressed", this, "_show_preview_text"); + + /////////////////////////////////////// + // PREVIEW PANEL + /////////////////////////////////////// + + preview_text = memnew(TextEdit); + main_box->add_child(preview_text); + preview_text->set_h_size_flags(SIZE_EXPAND_FILL); + preview_text->set_v_size_flags(SIZE_EXPAND_FILL); + preview_text->set_visible(preview_showed); + preview_text->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); + preview_text->set_syntax_coloring(true); + preview_text->set_readonly(true); + /////////////////////////////////////// // SHADER NODES TREE /////////////////////////////////////// @@ -2413,8 +2487,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeScalarFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -2507,10 +2581,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -2528,6 +2602,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside."))); add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants."))); add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index b5b00f2b5e..1556c7cd43 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -60,14 +60,18 @@ class VisualShaderEditor : public VBoxContainer { int editing_port; Ref<VisualShader> visual_shader; + HSplitContainer *main_box; GraphEdit *graph; ToolButton *add_node; + ToolButton *preview_shader; OptionButton *edit_type; PanelContainer *error_panel; Label *error_label; + TextEdit *preview_text; + UndoRedo *undo_redo; Point2 saved_node_pos; bool saved_node_pos_dirty; @@ -75,6 +79,8 @@ class VisualShaderEditor : public VBoxContainer { ConfirmationDialog *members_dialog; MenuButton *tools; + bool preview_showed; + enum ToolsMenuOptions { EXPAND_ALL, COLLAPSE_ALL @@ -146,6 +152,9 @@ class VisualShaderEditor : public VBoxContainer { void _update_custom_nodes(); void _update_options_menu(); + void _show_preview_text(); + void _update_preview(); + static VisualShaderEditor *singleton; void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 0f3c4c924a..a418773131 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -997,7 +997,6 @@ public: void load_projects(); void set_search_term(String p_search_term); - void set_filter_option(ProjectListFilter::FilterOption p_option); void set_order_option(ProjectListFilter::FilterOption p_option); void sort_projects(); int get_project_count() const; @@ -1030,7 +1029,6 @@ private: static void load_project_data(const String &p_property_key, Item &p_item, bool p_favorite); String _search_term; - ProjectListFilter::FilterOption _filter_option; ProjectListFilter::FilterOption _order_option; Set<String> _selected_project_keys; String _last_clicked; // Project key @@ -1063,7 +1061,6 @@ struct ProjectListComparator { }; ProjectList::ProjectList() { - _filter_option = ProjectListFilter::FILTER_NAME; _order_option = ProjectListFilter::FILTER_MODIFIED; _scroll_children = memnew(VBoxContainer); @@ -1303,12 +1300,6 @@ void ProjectList::set_search_term(String p_search_term) { _search_term = p_search_term; } -void ProjectList::set_filter_option(ProjectListFilter::FilterOption p_option) { - if (_filter_option != p_option) { - _filter_option = p_option; - } -} - void ProjectList::set_order_option(ProjectListFilter::FilterOption p_option) { if (_order_option != p_option) { _order_option = p_option; @@ -1328,11 +1319,18 @@ void ProjectList::sort_projects() { bool visible = true; if (_search_term != "") { - if (_filter_option == ProjectListFilter::FILTER_PATH) { - visible = item.path.findn(_search_term) != -1; - } else if (_filter_option == ProjectListFilter::FILTER_NAME) { - visible = item.project_name.findn(_search_term) != -1; + + String search_path; + if (_search_term.find("/") != -1) { + // Search path will match the whole path + search_path = item.path; + } else { + // Search path will only match the last path component to make searching more strict + search_path = item.path.get_file(); } + + // When searching, display projects whose name or path contain the search term + visible = item.project_name.findn(_search_term) != -1 || search_path.findn(_search_term) != -1; } item.control->set_visible(visible); @@ -1694,7 +1692,6 @@ void ProjectList::_bind_methods() { ClassDB::bind_method("_panel_input", &ProjectList::_panel_input); ClassDB::bind_method("_favorite_pressed", &ProjectList::_favorite_pressed); ClassDB::bind_method("_show_project", &ProjectList::_show_project); - //ClassDB::bind_method("_unhandled_input", &ProjectList::_unhandled_input); ADD_SIGNAL(MethodInfo(SIGNAL_SELECTION_CHANGED)); ADD_SIGNAL(MethodInfo(SIGNAL_PROJECT_ASK_OPEN)); @@ -1754,8 +1751,19 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) { if (k.is_valid()) { - if (!k->is_pressed()) + if (!k->is_pressed()) { return; + } + + // Pressing Command + Q quits the Project Manager + // This is handled by the platform implementation on macOS, + // so only define the shortcut on other platforms +#ifndef OSX_ENABLED + if (k->get_scancode_with_modifiers() == (KEY_MASK_CMD | KEY_Q)) { + _dim_window(); + get_tree()->quit(); + } +#endif if (tabs->get_current_tab() != 0) return; @@ -1834,7 +1842,6 @@ void ProjectManager::_unhandled_input(const Ref<InputEvent> &p_ev) { void ProjectManager::_load_recent_projects() { - _project_list->set_filter_option(project_filter->get_filter_option()); _project_list->set_order_option(project_order_filter->get_filter_option()); _project_list->set_search_term(project_filter->get_search_term()); _project_list->load_projects(); @@ -2198,7 +2205,6 @@ void ProjectManager::_on_order_option_changed() { } void ProjectManager::_on_filter_option_changed() { - _project_list->set_filter_option(project_filter->get_filter_option()); _project_list->set_search_term(project_filter->get_search_term()); _project_list->sort_projects(); } @@ -2270,6 +2276,9 @@ ProjectManager::ProjectManager() { } break; } + // Define a minimum window size to prevent UI elements from overlapping or being cut off + OS::get_singleton()->set_min_window_size(Size2(750, 420) * EDSCALE); + #ifndef OSX_ENABLED // The macOS platform implementation uses its own hiDPI window resizing code // TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below @@ -2295,26 +2304,11 @@ ProjectManager::ProjectManager() { VBoxContainer *vb = memnew(VBoxContainer); panel->add_child(vb); vb->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 8 * EDSCALE); - vb->add_constant_override("separation", 8 * EDSCALE); String cp; cp += 0xA9; OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2019 Juan Linietsky, Ariel Manzur & Godot Contributors"); - HBoxContainer *top_hb = memnew(HBoxContainer); - vb->add_child(top_hb); - Label *l = memnew(Label); - l->set_text(VERSION_NAME + String(" - ") + TTR("Project Manager")); - top_hb->add_child(l); - top_hb->add_spacer(); - l = memnew(Label); - String hash = String(VERSION_HASH); - if (hash.length() != 0) - hash = "." + hash.left(9); - l->set_text("v" VERSION_FULL_BUILD "" + hash); - l->set_align(Label::ALIGN_CENTER); - top_hb->add_child(l); - Control *center_box = memnew(Control); center_box->set_v_size_flags(SIZE_EXPAND_FILL); vb->add_child(center_box); @@ -2322,11 +2316,12 @@ ProjectManager::ProjectManager() { tabs = memnew(TabContainer); center_box->add_child(tabs); tabs->set_anchors_and_margins_preset(Control::PRESET_WIDE); + tabs->set_tab_align(TabContainer::ALIGN_LEFT); HBoxContainer *tree_hb = memnew(HBoxContainer); projects_hb = tree_hb; - projects_hb->set_name(TTR("Project List")); + projects_hb->set_name(TTR("Projects")); tabs->add_child(tree_hb); @@ -2343,6 +2338,7 @@ ProjectManager::ProjectManager() { sort_filter_titles.push_back("Path"); sort_filter_titles.push_back("Last Modified"); project_order_filter = memnew(ProjectListFilter); + project_order_filter->add_filter_option(); project_order_filter->_setup_filters(sort_filter_titles); project_order_filter->set_filter_size(150); sort_filters->add_child(project_order_filter); @@ -2353,21 +2349,12 @@ ProjectManager::ProjectManager() { project_order_filter->set_filter_option((ProjectListFilter::FilterOption)projects_sorting_order); sort_filters->add_spacer(true); - Label *search_label = memnew(Label); - search_label->set_text(TTR("Search:")); - sort_filters->add_child(search_label); - - HBoxContainer *search_filters = memnew(HBoxContainer); - Vector<String> vec2; - vec2.push_back("Name"); - vec2.push_back("Path"); + project_filter = memnew(ProjectListFilter); - project_filter->_setup_filters(vec2); project_filter->add_search_box(); - search_filters->add_child(project_filter); project_filter->connect("filter_changed", this, "_on_filter_option_changed"); project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE); - sort_filters->add_child(search_filters); + sort_filters->add_child(project_filter); search_tree_vb->add_child(sort_filters); @@ -2457,6 +2444,17 @@ ProjectManager::ProjectManager() { settings_hb->set_alignment(BoxContainer::ALIGN_END); settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN); + Label *version_label = memnew(Label); + String hash = String(VERSION_HASH); + if (hash.length() != 0) { + hash = "." + hash.left(9); + } + version_label->set_text("v" VERSION_FULL_BUILD "" + hash); + // Fade out the version label to be less prominent, but still readable + version_label->set_self_modulate(Color(1, 1, 1, 0.6)); + version_label->set_align(Label::ALIGN_CENTER); + settings_hb->add_child(version_label); + language_btn = memnew(OptionButton); language_btn->set_flat(true); language_btn->set_focus_mode(Control::FOCUS_NONE); @@ -2489,27 +2487,6 @@ ProjectManager::ProjectManager() { center_box->add_child(settings_hb); settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT); - CenterContainer *cc = memnew(CenterContainer); - Button *cancel = memnew(Button); - cancel->set_text(TTR("Exit")); - cancel->set_custom_minimum_size(Size2(100, 1) * EDSCALE); - -#ifndef OSX_ENABLED - // Pressing Command + Q quits the Project Manager - // This is handled by the platform implementation on macOS, - // so only define the shortcut on other platforms - InputEventKey *quit_key = memnew(InputEventKey); - quit_key->set_command(true); - quit_key->set_scancode(KEY_Q); - ShortCut *quit_shortcut = memnew(ShortCut); - quit_shortcut->set_shortcut(quit_key); - cancel->set_shortcut(quit_shortcut); -#endif - - cc->add_child(cancel); - cancel->connect("pressed", this, "_exit_dialog"); - vb->add_child(cc); - ////////////////////////////////////////////////////////////// language_restart_ask = memnew(ConfirmationDialog); @@ -2630,11 +2607,20 @@ void ProjectListFilter::_bind_methods() { ADD_SIGNAL(MethodInfo("filter_changed")); } +void ProjectListFilter::add_filter_option() { + filter_option = memnew(OptionButton); + filter_option->set_clip_text(true); + filter_option->connect("item_selected", this, "_filter_option_selected"); + add_child(filter_option); +} + void ProjectListFilter::add_search_box() { search_box = memnew(LineEdit); + search_box->set_placeholder(TTR("Search")); search_box->connect("text_changed", this, "_search_text_changed"); search_box->set_h_size_flags(SIZE_EXPAND_FILL); add_child(search_box); + has_search_box = true; } @@ -2645,13 +2631,6 @@ void ProjectListFilter::set_filter_size(int h_size) { ProjectListFilter::ProjectListFilter() { _current_filter = FILTER_NAME; - - filter_option = memnew(OptionButton); - set_filter_size(80); - filter_option->set_clip_text(true); - filter_option->connect("item_selected", this, "_filter_option_selected"); - add_child(filter_option); - has_search_box = false; } diff --git a/editor/project_manager.h b/editor/project_manager.h index 4ccb99d6bd..2a5fd02892 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -152,6 +152,7 @@ protected: public: void _setup_filters(Vector<String> options); + void add_filter_option(); void add_search_box(); void set_filter_size(int h_size); String get_search_term(); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 032b3a19a6..f1eb7adbd2 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -986,9 +986,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } else { new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root)); } + if (!new_node) { - ERR_EXPLAIN("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead."); new_node = memnew(Node); + ERR_PRINTS("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead."); } } else { switch (p_tool) { @@ -1537,10 +1538,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V Node *validate = new_parent; while (validate) { - if (p_nodes.find(validate) != -1) { - ERR_EXPLAIN("Selection changed at some point.. can't reparent"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point.. can't reparent."); validate = validate->get_parent(); } //ok all valid @@ -2253,8 +2251,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) { //drop at above selected node if (to_node == EditorNode::get_singleton()->get_edited_scene()) { to_node = NULL; - ERR_EXPLAIN("Cannot perform drop above the root node!"); - ERR_FAIL(); + ERR_FAIL_MSG("Cannot perform drop above the root node!"); } to_pos = to_node->get_index(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 2d9accc3d8..43f540e688 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -270,15 +270,30 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { item->add_button(0, get_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning()); } - bool has_connections = p_node->has_persistent_signal_connections(); - bool has_groups = p_node->has_persistent_groups(); - - if (has_connections && has_groups) { - item->add_button(0, get_icon("SignalsAndGroups", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connection(s) and group(s).\nClick to show signals dock.")); - } else if (has_connections) { - item->add_button(0, get_icon("Signals", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connections.\nClick to show signals dock.")); - } else if (has_groups) { - item->add_button(0, get_icon("Groups", "EditorIcons"), BUTTON_GROUPS, false, TTR("Node is in group(s).\nClick to show groups dock.")); + int num_connections = p_node->get_persistent_signal_connection_count(); + int num_groups = p_node->get_persistent_group_count(); + + if (num_connections >= 1 && num_groups >= 1) { + item->add_button( + 0, + get_icon("SignalsAndGroups", "EditorIcons"), + BUTTON_SIGNALS, + false, + vformat(TTR("Node has %s connection(s) and %s group(s).\nClick to show signals dock."), num_connections, num_groups)); + } else if (num_connections >= 1) { + item->add_button( + 0, + get_icon("Signals", "EditorIcons"), + BUTTON_SIGNALS, + false, + vformat(TTR("Node has %s connection(s).\nClick to show signals dock."), num_connections)); + } else if (num_groups >= 1) { + item->add_button( + 0, + get_icon("Groups", "EditorIcons"), + BUTTON_GROUPS, + false, + vformat(TTR("Node is in %s group(s).\nClick to show groups dock."), num_groups)); } } @@ -995,6 +1010,17 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d return true; } + if (String(d["type"]) == "script_list_element") { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(d["script_list_element"]); + if (se) { + String sp = se->get_edited_resource()->get_path(); + if (_is_script_type(EditorFileSystem::get_singleton()->get_file_type(sp))) { + tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); + return true; + } + } + } + return String(d["type"]) == "nodes"; } void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { @@ -1032,6 +1058,16 @@ void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, emit_signal("files_dropped", files, np, section); } } + + if (String(d["type"]) == "script_list_element") { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(d["script_list_element"]); + if (se) { + String sp = se->get_edited_resource()->get_path(); + if (_is_script_type(EditorFileSystem::get_singleton()->get_file_type(sp))) { + emit_signal("script_dropped", sp, np); + } + } + } } void SceneTreeEditor::_rmb_select(const Vector2 &p_pos) { diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index fd0d36eddf..f1b3fa2ac6 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -242,7 +242,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_ //check if edge and poly share a vertex, of so, assign it to segment_idx for (int i = 0; i < points.size(); i++) { for (int j = 0; j < 2; j++) { - if (Math::is_zero_approx(segment[j].distance_to(points[i].point))) { + if (segment[j] == points[i].point) { segment_idx[j] = i; inserted_points.push_back(i); break; @@ -310,7 +310,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_ Vector2 edgeseg[2] = { points[edges[i].points[0]].point, points[edges[i].points[1]].point }; Vector2 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg); - if (Math::is_zero_approx(closest.distance_to(segment[j]))) { + if (closest == segment[j]) { //point rest of this edge res = closest; found = true; @@ -439,7 +439,7 @@ void CSGBrushOperation::BuildPoly::clip(const CSGBrush *p_brush, int p_face, Mes //transform A points to 2D - if (Math::is_zero_approx(segment[0].distance_to(segment[1]))) + if (segment[0] == segment[1]) return; //too small _clip_segment(p_brush, p_face, segment, mesh_merge, p_for_B); @@ -461,10 +461,10 @@ void CSGBrushOperation::_collision_callback(const CSGBrush *A, int p_face_a, Map { //check if either is a degenerate - if (Math::is_zero_approx(va[0].distance_to(va[1])) || Math::is_zero_approx(va[0].distance_to(va[2])) || Math::is_zero_approx(va[1].distance_to(va[2]))) + if (va[0] == va[1] || va[0] == va[2] || va[1] == va[2]) return; - if (Math::is_zero_approx(vb[0].distance_to(vb[1])) || Math::is_zero_approx(vb[0].distance_to(vb[2])) || Math::is_zero_approx(vb[1].distance_to(vb[2]))) + if (vb[0] == vb[1] || vb[0] == vb[2] || vb[1] == vb[2]) return; } diff --git a/modules/etc/texture_loader_pkm.cpp b/modules/etc/texture_loader_pkm.cpp index 3337460dfc..dd61d816d4 100644 --- a/modules/etc/texture_loader_pkm.cpp +++ b/modules/etc/texture_loader_pkm.cpp @@ -62,10 +62,8 @@ RES ResourceFormatPKM::load(const String &p_path, const String &p_original_path, f->set_endian_swap(true); ETC1Header h; - ERR_EXPLAIN("Invalid or Unsupported PKM texture file: " + p_path); f->get_buffer((uint8_t *)&h.tag, sizeof(h.tag)); - if (strncmp(h.tag, "PKM 10", sizeof(h.tag))) - ERR_FAIL_V(RES()); + ERR_FAIL_COND_V_MSG(strncmp(h.tag, "PKM 10", sizeof(h.tag)), RES(), "Invalid or unsupported PKM texture file: " + p_path + "."); h.format = f->get_16(); h.texWidth = f->get_16(); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 9f65a9fff1..7c01e85ff7 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -634,7 +634,7 @@ static GDScriptCompletionIdentifier _type_from_gdtype(const GDScriptDataType &p_ switch (p_gdtype.kind) { case GDScriptDataType::UNINITIALIZED: { - ERR_EXPLAIN("Uninitialized completion. Please report a bug."); + ERR_PRINT("Uninitialized completion. Please report a bug."); } break; case GDScriptDataType::BUILTIN: { ci.type.kind = GDScriptParser::DataType::BUILTIN; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 9a25e788c7..764f57aaa1 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -5761,7 +5761,7 @@ GDScriptParser::DataType GDScriptParser::_type_from_gdtype(const GDScriptDataTyp switch (p_gdtype.kind) { case GDScriptDataType::UNINITIALIZED: { - ERR_EXPLAIN("Uninitialized datatype. Please report a bug."); + ERR_PRINT("Uninitialized datatype. Please report a bug."); } break; case GDScriptDataType::BUILTIN: { result.kind = DataType::BUILTIN; diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index e610619b54..1abf26bfee 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -37,7 +37,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force String header = f->get_token(); - ERR_FAIL_COND_V(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED); + ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + "."); while (true) { String line = f->get_line(); @@ -45,12 +45,9 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force if (line == "") // empty line indicates end of header break; if (line.begins_with("FORMAT=")) { // leave option to implement other commands - if (line != "FORMAT=32-bit_rle_rgbe") { - ERR_EXPLAIN("Only 32-bit_rle_rgbe is supported for HDR files."); - return ERR_FILE_UNRECOGNIZED; - } + ERR_FAIL_COND_V_MSG(line != "FORMAT=32-bit_rle_rgbe", ERR_FILE_UNRECOGNIZED, "Only 32-bit_rle_rgbe is supported for HDR files."); } else if (!line.begins_with("#")) { // not comment - WARN_PRINTS("Ignoring unsupported header information in HDR : " + line); + WARN_PRINTS("Ignoring unsupported header information in HDR: " + line + "."); } } diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 8986e49cf0..d1bfa20842 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -106,8 +106,7 @@ static Ref<Image> _webp_lossy_unpack(const PoolVector<uint8_t> &p_buffer) { errdec = WebPDecodeRGBInto(&r[4], size, dst_w.ptr(), datasize, 3 * features.width) == NULL; } - //ERR_EXPLAIN("Error decoding webp! - "+p_file); - ERR_FAIL_COND_V(errdec, Ref<Image>()); + ERR_FAIL_COND_V_MSG(errdec, Ref<Image>(), "Failed decoding WebP image."); dst_w.release(); @@ -121,7 +120,6 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p WebPBitstreamFeatures features; if (WebPGetFeatures(p_buffer, p_buffer_len, &features) != VP8_STATUS_OK) { - // ERR_EXPLAIN("Error decoding WEBP image"); ERR_FAIL_V(ERR_FILE_CORRUPT); } @@ -138,8 +136,7 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p } dst_w.release(); - //ERR_EXPLAIN("Error decoding webp!"); - ERR_FAIL_COND_V(errdec, ERR_FILE_CORRUPT); + ERR_FAIL_COND_V_MSG(errdec, ERR_FILE_CORRUPT, "Failed decoding WebP image."); p_image->create(features.width, features.height, 0, features.has_alpha ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8, dst_image); diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index 62f09bfbf9..dd86c758bf 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -265,7 +265,10 @@ Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, cons ERR_FAIL_COND_V(p_to == p_from, FAILED); - return get_peer(p_to)->put_packet(p_buffer, p_buffer_size); // Sending to specific peer + Ref<WebSocketPeer> peer_to = get_peer(p_to); + ERR_FAIL_COND_V(peer_to.is_null(), FAILED); + + return peer_to->put_packet(p_buffer, p_buffer_size); // Sending to specific peer } } @@ -296,8 +299,6 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u ERR_FAIL_COND(type != SYS_NONE); // Only server sends sys messages ERR_FAIL_COND(from != p_peer_id); // Someone is cheating - _server_relay(from, to, in_buffer, size); // Relay if needed - if (to == 1) { // This is for the server _store_pkt(from, to, in_buffer, data_size); @@ -312,13 +313,9 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u // All but one, for us if not excluded if (_peer_id != -(int32_t)p_peer_id) _store_pkt(from, to, in_buffer, data_size); - - } else { - - // Send to specific peer - ERR_FAIL_COND(!_peer_map.has(to)); - get_peer(to)->put_packet(in_buffer, size); } + // Relay if needed (i.e. "to" includes a peer that is not the server) + _server_relay(from, to, in_buffer, size); } else { diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index cf2ad55b4a..0006a057e0 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -121,17 +121,17 @@ bool WSLClient::_verify_headers(String &r_protocol) { headers[name] = value; } -#define _WLS_EXPLAIN(NAME, VALUE) \ - ERR_EXPLAIN("Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'"); -#define _WLS_CHECK(NAME, VALUE) \ - _WLS_EXPLAIN(NAME, VALUE); \ - ERR_FAIL_COND_V(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false); -#define _WLS_CHECK_NC(NAME, VALUE) \ - _WLS_EXPLAIN(NAME, VALUE); \ - ERR_FAIL_COND_V(!headers.has(NAME) || headers[NAME] != VALUE, false); - _WLS_CHECK("connection", "upgrade"); - _WLS_CHECK("upgrade", "websocket"); - _WLS_CHECK_NC("sec-websocket-accept", WSLPeer::compute_key_response(_key)); +#define _WSL_CHECK(NAME, VALUE) \ + ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \ + "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'."); +#define _WSL_CHECK_NC(NAME, VALUE) \ + ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME] != VALUE, false, \ + "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'."); + _WSL_CHECK("connection", "upgrade"); + _WSL_CHECK("upgrade", "websocket"); + _WSL_CHECK_NC("sec-websocket-accept", WSLPeer::compute_key_response(_key)); +#undef _WSL_CHECK_NC +#undef _WSL_CHECK if (_protocols.size() == 0) { // We didn't request a custom protocol ERR_FAIL_COND_V(headers.has("sec-websocket-protocol"), false); @@ -148,10 +148,6 @@ bool WSLClient::_verify_headers(String &r_protocol) { if (!valid) return false; } -#undef _WLS_CHECK_NC -#undef _WLS_CHECK -#undef _WLS_EXPLAIN - return true; } diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index 1feae420b9..efb526eed1 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* lws_server.cpp */ +/* wsl_server.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -64,18 +64,17 @@ bool WSLServer::PendingPeer::_parse_request(const PoolStringArray p_protocols) { else headers[name] = value; } -#define _WLS_CHECK(NAME, VALUE) \ - ERR_EXPLAIN("Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'"); \ - ERR_FAIL_COND_V(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false); -#define _WLS_CHECK_EX(NAME) \ - ERR_EXPLAIN("Missing header '" + String(NAME) + "'."); \ - ERR_FAIL_COND_V(!headers.has(NAME), false); - _WLS_CHECK("upgrade", "websocket"); - _WLS_CHECK("sec-websocket-version", "13"); - _WLS_CHECK_EX("sec-websocket-key"); - _WLS_CHECK_EX("connection"); -#undef _WLS_CHECK_EX -#undef _WLS_CHECK +#define _WSL_CHECK(NAME, VALUE) \ + ERR_FAIL_COND_V_MSG(!headers.has(NAME) || headers[NAME].to_lower() != VALUE, false, \ + "Missing or invalid header '" + String(NAME) + "'. Expected value '" + VALUE + "'."); +#define _WSL_CHECK_EX(NAME) \ + ERR_FAIL_COND_V_MSG(!headers.has(NAME), false, "Missing header '" + String(NAME) + "'."); + _WSL_CHECK("upgrade", "websocket"); + _WSL_CHECK("sec-websocket-version", "13"); + _WSL_CHECK_EX("sec-websocket-key"); + _WSL_CHECK_EX("connection"); +#undef _WSL_CHECK_EX +#undef _WSL_CHECK key = headers["sec-websocket-key"]; if (headers.has("sec-websocket-protocol")) { Vector<String> protos = headers["sec-websocket-protocol"].split(","); diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp index c18aa04336..04911301ff 100644 --- a/modules/xatlas_unwrap/register_types.cpp +++ b/modules/xatlas_unwrap/register_types.cpp @@ -29,11 +29,14 @@ /*************************************************************************/ #include "register_types.h" + #include "core/error_macros.h" + #include "thirdparty/xatlas/xatlas.h" #include <stdio.h> #include <stdlib.h> + extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y); bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, const int *p_face_materials, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) { diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp index f644db462b..5cf28d6c89 100644 --- a/scene/2d/navigation_2d.cpp +++ b/scene/2d/navigation_2d.cpp @@ -551,7 +551,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect left_poly = p; portal_left = apex_point; portal_right = apex_point; - if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point))) + if (!path.size() || path[path.size() - 1] != apex_point) path.push_back(apex_point); skip = true; } @@ -569,7 +569,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect right_poly = p; portal_right = apex_point; portal_left = apex_point; - if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_to(apex_point))) + if (!path.size() || path[path.size() - 1] != apex_point) path.push_back(apex_point); } } diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index f2f53d4354..55c8c7f229 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -110,7 +110,7 @@ void Path2D::_notification(int p_what) { real_t frac = j / 8.0; Vector2 p = curve->interpolate(i, frac); - draw_line(prev_p, p, color, line_width); + draw_line(prev_p, p, color, line_width, true); prev_p = p; } } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 30aeebfdac..051f832882 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1200,7 +1200,9 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float } } - _stop_playing_caches(); + if (get_current_animation() != p_name) { + _stop_playing_caches(); + } c.current.from = &animation_set[name]; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index f1bdbb5ff5..7305d7459c 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -400,6 +400,7 @@ void FileDialog::update_file_list() { TreeItem *root = tree->create_item(); Ref<Texture> folder = get_icon("folder"); + const Color folder_color = get_color("folder"); List<String> files; List<String> dirs; @@ -429,6 +430,7 @@ void FileDialog::update_file_list() { TreeItem *ti = tree->create_item(root); ti->set_text(0, dir_name); ti->set_icon(0, folder); + ti->set_icon_color(0, folder_color); Dictionary d; d["name"] = dir_name; diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 38005f1322..fdffb26cb5 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -776,10 +776,16 @@ void GraphEdit::_top_layer_draw() { _draw_cos_line(top_layer, pos, topos, col, col); } - if (box_selecting) + if (box_selecting) { top_layer->draw_rect( box_selecting_rect, - get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); + get_color("box_selection_fill_color", "Editor")); + + top_layer->draw_rect( + box_selecting_rect, + get_color("box_selection_stroke_color", "Editor"), + false); + } } void GraphEdit::set_selected(Node *p_child) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c0eaf21215..a771794f25 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -129,7 +129,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const { int len = text[p_line].data.length(); const CharType *str = text[p_line].data.c_str(); - //update width + // Update width. for (int i = 0; i < len; i++) { w += get_char_width(str[i], str[i + 1], w); @@ -139,7 +139,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const { text.write[p_line].wrap_amount_cache = -1; - //update regions + // Update regions. text.write[p_line].region_info.clear(); @@ -148,7 +148,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const { if (!_is_symbol(str[i])) continue; if (str[i] == '\\') { - i++; //skip quoted anything + i++; // Skip quoted anything. continue; } @@ -275,7 +275,7 @@ void TextEdit::Text::clear() { } int TextEdit::Text::get_max_width(bool p_exclude_hidden) const { - //quite some work.. but should be fast enough. + // Quite some work, but should be fast enough. int max = 0; for (int i = 0; i < text.size(); i++) { @@ -323,7 +323,7 @@ int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const { if (left == 0) w = tab_w; else - w = tab_w - px % tab_w; // is right... + w = tab_w - px % tab_w; // Is right. } else { w = font->get_char_size(c, next_c).width; @@ -370,20 +370,18 @@ void TextEdit::_update_scrollbars() { bool use_hscroll = true; bool use_vscroll = true; + // Thanks yessopie for this clever bit of logic. if (total_rows <= visible_rows && total_width <= visible_width) { - //thanks yessopie for this clever bit of logic + use_hscroll = false; use_vscroll = false; - } else { if (total_rows > visible_rows && total_width <= visible_width) { - //thanks yessopie for this clever bit of logic use_hscroll = false; } if (total_rows <= visible_rows && total_width > visible_width) { - //thanks yessopie for this clever bit of logic use_vscroll = false; } } @@ -481,7 +479,7 @@ void TextEdit::_update_selection_mode_word() { String line = text[row]; int beg = CLAMP(col, 0, line.length()); - // if its the first selection and on whitespace make sure we grab the word instead.. + // If its the first selection and on whitespace make sure we grab the word instead. if (!selection.active) { while (beg > 0 && line[beg] <= 32) { beg--; @@ -490,7 +488,7 @@ void TextEdit::_update_selection_mode_word() { int end = beg; bool symbol = beg < line.length() && _is_symbol(line[beg]); - // get the word end and begin points + // Get the word end and begin points. while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) { beg--; } @@ -501,7 +499,7 @@ void TextEdit::_update_selection_mode_word() { end += 1; } - // initial selection + // Initial selection. if (!selection.active) { select(row, beg, row, end); selection.selecting_column = beg; @@ -537,11 +535,11 @@ void TextEdit::_update_selection_mode_line() { col = 0; if (row < selection.selecting_line) { - // cursor is above us + // Cursor is above us. cursor_set_line(row - 1, false); selection.selecting_column = text[selection.selecting_line].length(); } else { - // cursor is below us + // Cursor is below us. cursor_set_line(row + 1, false); selection.selecting_column = 0; col = text[row].length(); @@ -607,7 +605,7 @@ void TextEdit::_notification(int p_what) { case NOTIFICATION_DRAW: { if (first_draw) { - //size may not be the final one, so attempts to ensure cursor was visible may have failed + // Size may not be the final one, so attempts to ensure cursor was visible may have failed. adjust_viewport_to_cursor(); first_draw = false; } @@ -661,7 +659,7 @@ void TextEdit::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true); int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width; int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT); - //let's do it easy for now: + // Let's do it easy for now. cache.style_normal->draw(ci, Rect2(Point2(), size)); if (readonly) { cache.style_readonly->draw(ci, Rect2(Point2(), size)); @@ -701,7 +699,7 @@ void TextEdit::_notification(int p_what) { if (brace_matching_enabled && cursor.line >= 0 && cursor.line < text.size() && cursor.column >= 0) { if (cursor.column < text[cursor.line].length()) { - //check for open + // Check for open. CharType c = text[cursor.line][cursor.column]; CharType closec = 0; @@ -723,7 +721,7 @@ void TextEdit::_notification(int p_what) { for (int j = from; j < text[i].length(); j++) { CharType cc = text[i][j]; - //ignore any brackets inside a string + // Ignore any brackets inside a string. if (cc == '"' || cc == '\'') { CharType quotation = cc; do { @@ -732,7 +730,7 @@ void TextEdit::_notification(int p_what) { break; } cc = text[i][j]; - //skip over escaped quotation marks inside strings + // Skip over escaped quotation marks inside strings. if (cc == '\\') { bool escaped = true; while (j + 1 < text[i].length() && text[i][j + 1] == '\\') { @@ -789,7 +787,7 @@ void TextEdit::_notification(int p_what) { for (int j = from; j >= 0; j--) { CharType cc = text[i][j]; - //ignore any brackets inside a string + // Ignore any brackets inside a string. if (cc == '"' || cc == '\'') { CharType quotation = cc; do { @@ -798,7 +796,7 @@ void TextEdit::_notification(int p_what) { break; } cc = text[i][j]; - //skip over escaped quotation marks inside strings + // Skip over escaped quotation marks inside strings. if (cc == quotation) { bool escaped = false; while (j - 1 >= 0 && text[i][j - 1] == '\\') { @@ -837,10 +835,10 @@ void TextEdit::_notification(int p_what) { Point2 cursor_pos; int cursor_insert_offset_y = 0; - // get the highlighted words + // Get the highlighted words. String highlighted_text = get_selection_text(); - // check if highlighted words contains only whitespaces (tabs or spaces) + // Check if highlighted words contains only whitespaces (tabs or spaces). bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String(); String line_num_padding = line_numbers_zero_padded ? "0" : " "; @@ -875,7 +873,7 @@ void TextEdit::_notification(int p_what) { if (syntax_coloring) { color_map = _get_line_syntax_highlighting(line); } - // ensure we at least use the font color + // Ensure we at least use the font color. Color current_color = readonly ? cache.font_color_readonly : cache.font_color; bool underlined = false; @@ -916,7 +914,7 @@ void TextEdit::_notification(int p_what) { if (smooth_scroll_enabled) ofs_y += (-get_v_scroll_offset()) * get_row_height(); - // check if line contains highlighted word + // Check if line contains highlighted word. int highlighted_text_col = -1; int search_text_col = -1; int highlighted_word_col = -1; @@ -938,25 +936,25 @@ void TextEdit::_notification(int p_what) { } if (str.length() == 0) { - // draw line background if empty as we won't loop at at all + // Draw line background if empty as we won't loop at at all. if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color); } - // give visual indication of empty selected line + // Give visual indication of empty selected line. if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) { int char_w = cache.font->get_char_size(' ').width; VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color); } } else { - // if it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later. + // If it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later. if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg, get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg + ofs_x, get_row_height()), cache.current_line_color); } } if (line_wrap_index == 0) { - // only do these if we are on the first wrapped part of a line + // Only do these if we are on the first wrapped part of a line. if (text.is_breakpoint(line) && !draw_breakpoint_gutter) { #ifdef TOOLS_ENABLED @@ -966,7 +964,7 @@ void TextEdit::_notification(int p_what) { #endif } - // draw bookmark marker + // Draw bookmark marker. if (text.is_bookmark(line)) { if (draw_bookmark_gutter) { int vertical_gap = (get_row_height() * 40) / 100; @@ -976,26 +974,26 @@ void TextEdit::_notification(int p_what) { } } - // draw breakpoint marker + // Draw breakpoint marker. if (text.is_breakpoint(line)) { if (draw_breakpoint_gutter) { int vertical_gap = (get_row_height() * 40) / 100; int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; int marker_height = get_row_height() - (vertical_gap * 2); int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2); - // no transparency on marker + // No transparency on marker. VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b)); } } - // draw info icons + // Draw info icons. if (draw_info_gutter && text.has_info_icon(line)) { int vertical_gap = (get_row_height() * 40) / 100; int horizontal_gap = (cache.info_gutter_width * 30) / 100; int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width; Ref<Texture> info_icon = text.get_info_icon(line); - // ensure the icon fits the gutter size + // Ensure the icon fits the gutter size. Size2i icon_size = info_icon->get_size(); if (icon_size.width > cache.info_gutter_width - horizontal_gap) { icon_size.width = cache.info_gutter_width - horizontal_gap; @@ -1013,7 +1011,7 @@ void TextEdit::_notification(int p_what) { draw_texture_rect(info_icon, Rect2(icon_pos, icon_size)); } - // draw execution marker + // Draw execution marker. if (executing_line == line) { if (draw_breakpoint_gutter) { int icon_extra_size = 4; @@ -1031,7 +1029,7 @@ void TextEdit::_notification(int p_what) { } } - // draw fold markers + // Draw fold markers. if (draw_fold_gutter) { int horizontal_gap = (cache.fold_gutter_width * 30) / 100; int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w + cache.info_gutter_width; @@ -1046,7 +1044,7 @@ void TextEdit::_notification(int p_what) { } } - // draw line numbers + // Draw line numbers. if (cache.line_number_w) { int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2; String fc = String::num(line + 1); @@ -1058,32 +1056,35 @@ void TextEdit::_notification(int p_what) { } } - //loop through characters in one line + // Loop through characters in one line. for (int j = 0; j < str.length(); j++) { if (syntax_coloring) { if (color_map.has(last_wrap_column + j)) { - current_color = readonly ? cache.font_color_readonly : color_map[last_wrap_column + j].color; + current_color = color_map[last_wrap_column + j].color; + if (readonly && current_color.a > cache.font_color_readonly.a) { + current_color.a = cache.font_color_readonly.a; + } } color = current_color; } int char_w; - //handle tabulator + // Handle tabulator. char_w = text.get_char_width(str[j], str[j + 1], char_ofs); if ((char_ofs + char_margin) < xmargin_beg) { char_ofs += char_w; - // line highlighting handle horizontal clipping + // Line highlighting handle horizontal clipping. if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { if (j == str.length() - 1) { - // end of line when last char is skipped + // End of line when last char is skipped. VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color); } else if ((char_ofs + char_margin) > xmargin_beg) { - // char next to margin is skipped + // Char next to margin is skipped. VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, (char_ofs + char_margin) - (xmargin_beg + ofs_x), get_row_height()), cache.current_line_color); } } @@ -1097,7 +1098,7 @@ void TextEdit::_notification(int p_what) { bool in_search_result = false; if (search_text_col != -1) { - // if we are at the end check for new search result on same line + // If we are at the end check for new search result on same line. if (j >= search_text_col + search_text.length()) search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j); @@ -1108,19 +1109,19 @@ void TextEdit::_notification(int p_what) { } } - //current line highlighting + // Current line highlighting. bool in_selection = (selection.active && line >= selection.from_line && line <= selection.to_line && (line > selection.from_line || last_wrap_column + j >= selection.from_column) && (line < selection.to_line || last_wrap_column + j < selection.to_column)); if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { - // draw the wrap indent offset highlight + // Draw the wrap indent offset highlight. if (line_wrap_index != 0 && j == 0) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + ofs_x - indent_px, ofs_y, indent_px, get_row_height()), cache.current_line_color); } - // if its the last char draw to end of the line + // If its the last char draw to end of the line. if (j == str.length() - 1) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color); } - // actual text + // Actual text. if (!in_selection) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color); } @@ -1145,14 +1146,14 @@ void TextEdit::_notification(int p_what) { if (highlight_all_occurrences && !only_whitespaces_highlighted) { if (highlighted_text_col != -1) { - // if we are at the end check for new word on same line + // If we are at the end check for new word on same line. if (j > highlighted_text_col + highlighted_text.length()) { highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j); } bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col + highlighted_text.length()); - // if this is the original highlighted text we don't want to highlight it again + // If this is the original highlighted text we don't want to highlight it again. if (cursor.line == line && cursor_wrap_index == line_wrap_index && (cursor.column >= highlighted_text_col && cursor.column <= highlighted_text_col + highlighted_text.length())) { in_highlighted_word = false; } @@ -1349,7 +1350,7 @@ void TextEdit::_notification(int p_what) { bool completion_below = false; if (completion_active) { - // code completion box + // Code completion box. Ref<StyleBox> csb = get_stylebox("completion"); int maxlines = get_constant("completion_lines"); int cmax_width = get_constant("completion_max_width") * cache.font->get_char_size('x').x; @@ -1371,7 +1372,7 @@ void TextEdit::_notification(int p_what) { w = cmax_width; } - // Add space for completion icons + // Add space for completion icons. const int icon_hsep = get_constant("hseparation", "ItemList"); Size2 icon_area_size(get_row_height(), get_row_height()); w += icon_area_size.width + icon_hsep; @@ -1418,7 +1419,7 @@ void TextEdit::_notification(int p_what) { int yofs = (get_row_height() - cache.font->get_height()) / 2; Point2 title_pos(completion_rect.position.x, completion_rect.position.y + i * get_row_height() + cache.font->get_ascent() + yofs); - //draw completion icon if it is valid + // Draw completion icon if it is valid. Ref<Texture> icon = completion_options[l].icon; Rect2 icon_area(completion_rect.position.x, completion_rect.position.y + i * get_row_height(), icon_area_size.width, icon_area_size.height); if (icon.is_valid()) { @@ -1434,7 +1435,7 @@ void TextEdit::_notification(int p_what) { } if (scrollw) { - //draw a small scroll rectangle to show a position in the options + // Draw a small scroll rectangle to show a position in the options. float r = maxlines / (float)completion_options.size(); float o = line_from / (float)completion_options.size(); draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scrollw, completion_rect.size.y * r), scrollc); @@ -1443,7 +1444,7 @@ void TextEdit::_notification(int p_what) { completion_line_ofs = line_from; } - // check to see if the hint should be drawn + // Check to see if the hint should be drawn. bool show_hint = false; if (completion_hint != "") { if (completion_active) { @@ -1662,9 +1663,9 @@ void TextEdit::backspace_at_cursor() { _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { - // handle space indentation + // Handle space indentation. if (cursor.column != 0 && indent_using_spaces) { - // check if there are no other chars before cursor, just indentation + // Check if there are no other chars before cursor, just indentation. bool unindent = true; int i = 0; while (i < cursor.column && i < text[cursor.line].length()) { @@ -1675,10 +1676,9 @@ void TextEdit::backspace_at_cursor() { i++; } - // then we can remove all spaces as a single character. + // Then we can remove all spaces as a single character. if (unindent) { - // we want to remove spaces up to closest indent - // or whole indent if cursor is pointing at it + // We want to remove spaces up to closest indent, or whole indent if cursor is pointing at it. int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column); prev_column = cursor.column - spaces_to_delete; _remove_text(cursor.line, prev_column, cursor.line, cursor.column); @@ -1699,8 +1699,8 @@ void TextEdit::indent_right() { int start_line; int end_line; - // this value informs us by how much we changed selection position by indenting right - // default is 1 for tab indentation + // This value informs us by how much we changed selection position by indenting right. + // Default is 1 for tab indentation. int selection_offset = 1; begin_complex_operation(); @@ -1712,7 +1712,7 @@ void TextEdit::indent_right() { end_line = start_line; } - // ignore if the cursor is not past the first column + // Ignore if the cursor is not past the first column. if (is_selection_active() && get_selection_to_column() == 0) { end_line--; } @@ -1720,10 +1720,10 @@ void TextEdit::indent_right() { for (int i = start_line; i <= end_line; i++) { String line_text = get_line(i); if (indent_using_spaces) { - // we don't really care where selection is - we just need to know indentation level at the beginning of the line + // We don't really care where selection is - we just need to know indentation level at the beginning of the line. int left = _find_first_non_whitespace_column_of_line(line_text); int spaces_to_add = _calculate_spaces_till_next_right_indent(left); - // since we will add this much spaces we want move whole selection and cursor by this much + // Since we will add this much spaces we want move whole selection and cursor by this much. selection_offset = spaces_to_add; for (int j = 0; j < spaces_to_add; j++) line_text = ' ' + line_text; @@ -1733,7 +1733,7 @@ void TextEdit::indent_right() { set_line(i, line_text); } - // fix selection and cursor being off after shifting selection right + // Fix selection and cursor being off after shifting selection right. if (is_selection_active()) { select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset); } @@ -1747,10 +1747,9 @@ void TextEdit::indent_left() { int start_line; int end_line; - // moving cursor and selection after unindenting can get tricky - // because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either) - // therefore we just remember initial values - // and at the end of the operation offset them by number of removed characters + // Moving cursor and selection after unindenting can get tricky because + // changing content of line can move cursor and selection on it's own (if new line ends before previous position of either), + // therefore we just remember initial values and at the end of the operation offset them by number of removed characters. int removed_characters = 0; int initial_selection_end_column = selection.to_column; int initial_cursor_column = cursor.column; @@ -1765,7 +1764,7 @@ void TextEdit::indent_left() { end_line = start_line; } - // ignore if the cursor is not past the first column + // Ignore if the cursor is not past the first column. if (is_selection_active() && get_selection_to_column() == 0) { end_line--; } @@ -1779,12 +1778,12 @@ void TextEdit::indent_left() { set_line(i, line_text); removed_characters = 1; } else if (line_text.begins_with(" ")) { - // when unindenting we aim to remove spaces before line that has selection no matter what is selected + // When unindenting we aim to remove spaces before line that has selection no matter what is selected, // so we start of by finding first non whitespace character of line int left = _find_first_non_whitespace_column_of_line(line_text); - // here we remove only enough spaces to align text to nearest full multiple of indentation_size - // in case where selection begins at the start of indentation_size multiple we remove whole indentation level + // Here we remove only enough spaces to align text to nearest full multiple of indentation_size. + // In case where selection begins at the start of indentation_size multiple we remove whole indentation level. int spaces_to_remove = _calculate_spaces_till_next_left_indent(left); line_text = line_text.substr(spaces_to_remove, line_text.length()); @@ -1793,7 +1792,7 @@ void TextEdit::indent_left() { } } - // fix selection and cursor being off by one on the last line + // Fix selection and cursor being off by one on the last line. if (is_selection_active() && last_line_text != get_line(end_line)) { select(selection.from_line, selection.from_column - removed_characters, selection.to_line, initial_selection_end_column - removed_characters); @@ -1834,7 +1833,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co } if (row < 0) - row = 0; //todo + row = 0; // TODO. int col = 0; @@ -1848,7 +1847,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co colx += cursor.x_ofs; col = get_char_pos_for_line(colx, row, wrap_index); if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) { - // move back one if we are at the end of the row + // Move back one if we are at the end of the row. Vector<String> rows2 = get_wrap_rows_text(row); int row_end_col = 0; for (int i = 0; i < wrap_index + 1; i++) { @@ -1942,7 +1941,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - // toggle breakpoint on gutter click + // Toggle breakpoint on gutter click. if (draw_breakpoint_gutter) { int gutter = cache.style_normal->get_margin(MARGIN_LEFT); if (mb->get_position().x > gutter - 6 && mb->get_position().x <= gutter + cache.breakpoint_gutter_width - 3) { @@ -1952,7 +1951,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - // emit info clicked + // Emit info clicked. if (draw_info_gutter && text.has_info_icon(row)) { int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); int gutter_left = left_margin + cache.breakpoint_gutter_width; @@ -1962,7 +1961,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - // toggle fold on gutter click if can + // Toggle fold on gutter click if can. if (draw_fold_gutter) { int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); @@ -1977,7 +1976,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - // unfold on folded icon click + // Unfold on folded icon click. if (is_folded(row)) { int line_width = text.get_line_width(row); line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.info_gutter_width + cache.fold_gutter_width - cursor.x_ofs; @@ -2044,9 +2043,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { - //if sel active and dblick last time < something - - //else selection.active = false; selection.selecting_mode = Selection::MODE_POINTER; selection.selecting_line = row; @@ -2054,14 +2050,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) { - //tripleclick select line + + // Triple-click select line. selection.selecting_mode = Selection::MODE_LINE; _update_selection_mode_line(); last_dblclk = 0; - } else if (mb->is_doubleclick() && text[cursor.line].length()) { - //doubleclick select word + // Double-click select word. selection.selecting_mode = Selection::MODE_WORD; _update_selection_mode_word(); last_dblclk = OS::get_singleton()->get_ticks_msec(); @@ -2086,7 +2082,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int to_column = get_selection_to_column(); if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { - // Right click is outside the selected text + // Right click is outside the selected text. deselect(); } } @@ -2107,7 +2103,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_LEFT) click_select_held->stop(); - // notify to show soft keyboard + // Notify to show soft keyboard. notification(NOTIFICATION_FOCUS_ENTER); } } @@ -2123,7 +2119,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } h_scroll->set_value(h_scroll->get_value() + pan_gesture->get_delta().x * 100); if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) - accept_event(); //accept event if scroll changed + accept_event(); // Accept event if scroll changed. return; } @@ -2148,7 +2144,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { //ignore if dragging + if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging. _reset_caret_blink_timer(); switch (selection.selecting_mode) { @@ -2169,13 +2165,13 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } if (v_scroll->get_value() != prev_v_scroll || h_scroll->get_value() != prev_h_scroll) - accept_event(); //accept event if scroll changed + accept_event(); // Accept event if scroll changed. Ref<InputEventKey> k = p_gui_input; if (k.is_valid()) { - k = k->duplicate(); //it will be modified later on + k = k->duplicate(); // It will be modified later on. #ifdef OSX_ENABLED if (k->get_scancode() == KEY_META) { @@ -2311,11 +2307,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _consume_pair_symbol(chr[0]); } else { - // remove the old character if in insert mode + // Remove the old character if in insert mode. if (insert_mode) { begin_complex_operation(); - // make sure we don't try and remove empty space + // Make sure we don't try and remove empty space. if (cursor.column < get_line(cursor.line).length()) { _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); } @@ -2337,9 +2333,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _cancel_completion(); } - /* TEST CONTROL FIRST!! */ + /* TEST CONTROL FIRST! */ - // some remaps for duplicate functions.. + // Some remaps for duplicate functions. if (k->get_command() && !k->get_shift() && !k->get_alt() && !k->get_metakey() && k->get_scancode() == KEY_INSERT) { k->set_scancode(KEY_C); @@ -2383,10 +2379,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _reset_caret_blink_timer(); - // save here for insert mode, just in case it is cleared in the following section + // Save here for insert mode, just in case it is cleared in the following section. bool had_selection = selection.active; - // stuff to do when selection is active.. + // Stuff to do when selection is active. if (!readonly && selection.active) { bool clear = false; @@ -2406,7 +2402,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; case KEY_X: case KEY_C: - //special keys often used with control, wait... + // Special keys often used with control, wait. clear = (!k->get_command() || k->get_shift() || k->get_alt()); break; case KEY_DELETE: @@ -2431,7 +2427,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { case KEY_PAGEDOWN: case KEY_HOME: case KEY_END: - // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys) + // Ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys). if (k->get_command() || k->get_shift() || k->get_alt()) break; unselect = true; @@ -2469,7 +2465,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { bool scancode_handled = true; - // special scancode test... + // Special scancode test. switch (k->get_scancode()) { @@ -2481,7 +2477,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { String ins = "\n"; - //keep indentation + // Keep indentation. int space_count = 0; for (int i = 0; i < cursor.column; i++) { if (text[cursor.line][i] == '\t') { @@ -2512,10 +2508,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { bool brace_indent = false; - // no need to indent if we are going upwards. + // No need to indent if we are going upwards. if (auto_indent && !(k->get_command() && k->get_shift())) { - // indent once again if previous line will end with ':' or '{' and the line is not a comment - // (i.e. colon/brace precedes current cursor position) + // Indent once again if previous line will end with ':' or '{' and the line is not a comment + // (i.e. colon/brace precedes current cursor position). if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{') && !is_line_comment(cursor.line)) { if (indent_using_spaces) { ins += space_indent; @@ -2523,7 +2519,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { ins += "\t"; } - // no need to move the brace below if we are not taking the text with us. + // No need to move the brace below if we are not taking the text with us. if (text[cursor.line][cursor.column] == '}' && !k->get_command()) { brace_indent = true; ins += "\n" + ins.substr(1, ins.length() - 2); @@ -2565,7 +2561,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } break; case KEY_TAB: { - if (k->get_command()) break; // avoid tab when command + if (k->get_command()) break; // Avoid tab when command. if (readonly) break; @@ -2579,7 +2575,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (k->get_shift()) { - // simple unindent + // Simple unindent. int cc = cursor.column; const String &line = text[cursor.line]; @@ -2591,17 +2587,17 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (cc > 0 && cc <= text[cursor.line].length()) { if (text[cursor.line][cc - 1] == '\t') { - // tabs unindentation + // Tabs unindentation. _remove_text(cursor.line, cc - 1, cursor.line, cc); if (cursor.column >= left) cursor_set_column(MAX(0, cursor.column - 1)); update(); } else { - // spaces unindentation + // Spaces unindentation. int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); if (spaces_to_remove > 0) { _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); - if (cursor.column > left - spaces_to_remove) // inside text? + if (cursor.column > left - spaces_to_remove) // Inside text? cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); update(); } @@ -2611,9 +2607,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } } else { - // simple indent + // Simple indent. if (indent_using_spaces) { - // insert only as much spaces as needed till next indentation level + // Insert only as much spaces as needed till next indentation level. int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); String indent_to_insert = String(); for (int i = 0; i < spaces_to_add; i++) @@ -2641,20 +2637,20 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int line = cursor.line; int column = cursor.column; - // check if we are removing a single whitespace, if so remove it and the next char type - // else we just remove the whitespace + // Check if we are removing a single whitespace, if so remove it and the next char type, + // else we just remove the whitespace. bool only_whitespace = false; if (_is_whitespace(text[line][column - 1]) && _is_whitespace(text[line][column - 2])) { only_whitespace = true; } else if (_is_whitespace(text[line][column - 1])) { - // remove the single whitespace + // Remove the single whitespace. column--; } - // check if its a text char + // Check if its a text char. bool only_char = (_is_text_char(text[line][column - 1]) && !only_whitespace); - // if its not whitespace or char then symbol. + // If its not whitespace or char then symbol. bool only_symbols = !(only_whitespace || only_char); while (column > 0) { @@ -2940,7 +2936,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int curline_len = text[cursor.line].length(); if (cursor.line == text.size() - 1 && cursor.column == curline_len) - break; //nothing to do + break; // Nothing to do. int next_line = cursor.column < curline_len ? cursor.line : cursor.line + 1; int next_column; @@ -2957,20 +2953,20 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int line = cursor.line; int column = cursor.column; - // check if we are removing a single whitespace, if so remove it and the next char type - // else we just remove the whitespace + // Check if we are removing a single whitespace, if so remove it and the next char type, + // else we just remove the whitespace. bool only_whitespace = false; if (_is_whitespace(text[line][column]) && _is_whitespace(text[line][column + 1])) { only_whitespace = true; } else if (_is_whitespace(text[line][column])) { - // remove the single whitespace + // Remove the single whitespace. column++; } - // check if its a text char + // Check if its a text char. bool only_char = (_is_text_char(text[line][column]) && !only_whitespace); - // if its not whitespace or char then symbol. + // If its not whitespace or char then symbol. bool only_symbols = !(only_whitespace || only_char); while (column < curline_len) { @@ -3029,7 +3025,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_column(0); } else { - // move cursor column to start of wrapped row and then to start of text + // Move cursor column to start of wrapped row and then to start of text. Vector<String> rows = get_wrap_rows_text(cursor.line); int wi = get_cursor_wrap_index(); int row_start_col = 0; @@ -3037,7 +3033,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { row_start_col += rows[i].length(); } if (cursor.column == row_start_col || wi == 0) { - // compute whitespace symbols seq length + // Compute whitespace symbols seq length. int current_line_whitespace_len = 0; while (current_line_whitespace_len < text[cursor.line].length()) { CharType c = text[cursor.line][current_line_whitespace_len]; @@ -3088,7 +3084,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (k->get_command()) cursor_set_line(get_last_unhidden_line(), true, false, 9999); - // move cursor column to end of wrapped row and then to end of text + // Move cursor column to end of wrapped row and then to end of text. Vector<String> rows = get_wrap_rows_text(cursor.line); int wi = get_cursor_wrap_index(); int row_end_col = -1; @@ -3274,7 +3270,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; case KEY_SPACE: { #ifdef OSX_ENABLED - if (completion_enabled && k->get_metakey()) { //cmd-space is spotlight shortcut in OSX + if (completion_enabled && k->get_metakey()) { // cmd-space is spotlight shortcut in OSX #else if (completion_enabled && k->get_command()) { #endif @@ -3302,18 +3298,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - if (!scancode_handled && !k->get_command()) { //for German kbds + if (!scancode_handled && !k->get_command()) { // For German keyboards. if (k->get_unicode() >= 32) { if (readonly) return; - // remove the old character if in insert mode and no selection + // Remove the old character if in insert mode and no selection. if (insert_mode && !had_selection) { begin_complex_operation(); - // make sure we don't try and remove empty space + // Make sure we don't try and remove empty space. if (cursor.column < get_line(cursor.line).length()) { _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); } @@ -3424,10 +3420,10 @@ void TextEdit::_post_shift_selection() { void TextEdit::_scroll_lines_up() { scrolling = false; - // adjust the vertical scroll + // Adjust the vertical scroll. set_v_scroll(get_v_scroll() - 1); - // adjust the cursor to viewport + // Adjust the cursor to viewport. if (!selection.active) { int cur_line = cursor.line; int cur_wrap = get_cursor_wrap_index(); @@ -3443,10 +3439,10 @@ void TextEdit::_scroll_lines_up() { void TextEdit::_scroll_lines_down() { scrolling = false; - // adjust the vertical scroll + // Adjust the vertical scroll. set_v_scroll(get_v_scroll() + 1); - // adjust the cursor to viewport + // Adjust the cursor to viewport. if (!selection.active) { int cur_line = cursor.line; int cur_wrap = get_cursor_wrap_index(); @@ -3463,15 +3459,15 @@ void TextEdit::_scroll_lines_down() { void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, int &r_end_line, int &r_end_column) { - //save for undo... + // Save for undo. ERR_FAIL_INDEX(p_line, text.size()); ERR_FAIL_COND(p_char < 0); - /* STEP 1 remove \r from source text and separate in substrings */ + /* STEP 1: Remove \r from source text and separate in substrings. */ Vector<String> substrings = p_text.replace("\r", "").split("\n"); - /* STEP 2 fire breakpoint_toggled signals */ + /* STEP 2: Fire breakpoint_toggled signals. */ // Is this just a new empty line? bool shift_first_line = p_char == 0 && p_text.replace("\r", "") == "\n"; @@ -3487,19 +3483,19 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i } } - /* STEP 3 add spaces if the char is greater than the end of the line */ + /* STEP 3: Add spaces if the char is greater than the end of the line. */ while (p_char > text[p_line].length()) { text.set(p_line, text[p_line] + String::chr(' ')); } - /* STEP 4 separate dest string in pre and post text */ + /* STEP 4: Separate dest string in pre and post text. */ String preinsert_text = text[p_line].substr(0, p_char); String postinsert_text = text[p_line].substr(p_char, text[p_line].size()); for (int j = 0; j < substrings.size(); j++) { - //insert the substrings + // Insert the substrings. if (j == 0) { @@ -3544,8 +3540,8 @@ String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_lin ERR_FAIL_INDEX_V(p_from_column, text[p_from_line].length() + 1, String()); ERR_FAIL_INDEX_V(p_to_line, text.size(), String()); ERR_FAIL_INDEX_V(p_to_column, text[p_to_line].length() + 1, String()); - ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // from > to - ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // from > to + ERR_FAIL_COND_V(p_to_line < p_from_line, String()); // 'from > to'. + ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column < p_from_column, String()); // 'from > to'. String ret; @@ -3568,8 +3564,8 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li ERR_FAIL_INDEX(p_from_column, text[p_from_line].length() + 1); ERR_FAIL_INDEX(p_to_line, text.size()); ERR_FAIL_INDEX(p_to_column, text[p_to_line].length() + 1); - ERR_FAIL_COND(p_to_line < p_from_line); // from > to - ERR_FAIL_COND(p_to_line == p_from_line && p_to_column < p_from_column); // from > to + ERR_FAIL_COND(p_to_line < p_from_line); // 'from > to'. + ERR_FAIL_COND(p_to_line == p_from_line && p_to_column < p_from_column); // 'from > to'. String pre_text = text[p_from_line].substr(0, p_from_column); String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length()); @@ -3631,22 +3627,22 @@ void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r op.chain_forward = false; op.chain_backward = false; - //see if it should just be set as current op + // See if it should just be set as current op. if (current_op.type != op.type) { op.prev_version = get_version(); _push_current_op(); current_op = op; - return; //set as current op, return + return; // Set as current op, return. } - //see if it can be merged + // See if it can be merged. if (current_op.to_line != p_line || current_op.to_column != p_char) { op.prev_version = get_version(); _push_current_op(); current_op = op; - return; //set as current op, return + return; // Set as current op, return. } - //merge current op + // Merge current op. current_op.text += p_text; current_op.to_column = retchar; @@ -3670,7 +3666,7 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i if (!undo_enabled) return; - /* UNDO!! */ + /* UNDO! */ TextOperation op; op.type = TextOperation::TYPE_REMOVE; op.from_line = p_from_line; @@ -3682,27 +3678,20 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column, int p_to_line, i op.chain_forward = false; op.chain_backward = false; - //see if it should just be set as current op + // See if it should just be set as current op. if (current_op.type != op.type) { op.prev_version = get_version(); _push_current_op(); current_op = op; - return; //set as current op, return + return; // Set as current op, return. } - //see if it can be merged + // See if it can be merged. if (current_op.from_line == p_to_line && current_op.from_column == p_to_column) { - //basckace or similar + // Backspace or similar. current_op.text = text + current_op.text; current_op.from_line = p_from_line; current_op.from_column = p_from_column; - return; //update current op - } - if (current_op.from_line == p_from_line && current_op.from_column == p_from_column) { - - //current_op.text=text+current_op.text; - //current_op.from_line=p_from_line; - //current_op.from_column=p_from_column; - //return; //update current op + return; // Update current op. } op.prev_version = get_version(); @@ -3734,11 +3723,11 @@ int TextEdit::get_char_count() { for (int i = 0; i < text.size(); i++) { if (i > 0) - totalsize++; // incliude \n + totalsize++; // Include \n. totalsize += text[i].length(); } - return totalsize; // omit last \n + return totalsize; // Omit last \n. } Size2 TextEdit::get_minimum_size() const { @@ -3758,7 +3747,7 @@ int TextEdit::get_visible_rows() const { int TextEdit::get_total_visible_rows() const { - // returns the total amount of rows we need in the editor. + // Returns the total amount of rows we need in the editor. // This skips hidden lines and counts each wrapping of a line. if (!is_hiding_enabled() && !is_wrap_enabled()) return text.size(); @@ -3780,7 +3769,7 @@ void TextEdit::_update_wrap_at() { text.clear_wrap_cache(); for (int i = 0; i < text.size(); i++) { - // update all values that wrap + // Update all values that wrap. if (!line_wraps(i)) continue; Vector<String> rows = get_wrap_rows_text(i); @@ -3790,7 +3779,7 @@ void TextEdit::_update_wrap_at() { void TextEdit::adjust_viewport_to_cursor() { - // make sure cursor is visible on the screen + // Make sure cursor is visible on the screen. scrolling = false; int cur_line = cursor.line; @@ -3802,20 +3791,20 @@ void TextEdit::adjust_viewport_to_cursor() { int last_vis_wrap = get_last_visible_line_wrap_index(); if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) { - // cursor is above screen + // Cursor is above screen. set_line_as_first_visible(cur_line, cur_wrap); } else if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) { - // cursor is below screen + // Cursor is below screen. set_line_as_last_visible(cur_line, cur_wrap); } int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; - visible_width -= 20; // give it a little more space + visible_width -= 20; // Give it a little more space. if (!is_wrap_enabled()) { - // adjust x offset + // Adjust x offset. int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]); if (cursor_x > (cursor.x_ofs + visible_width)) @@ -3833,7 +3822,7 @@ void TextEdit::adjust_viewport_to_cursor() { void TextEdit::center_viewport_to_cursor() { - // move viewport so the cursor is in the center of the screen + // Move viewport so the cursor is in the center of the screen. scrolling = false; if (is_line_hidden(cursor.line)) @@ -3843,10 +3832,10 @@ void TextEdit::center_viewport_to_cursor() { int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - cache.info_gutter_width; if (v_scroll->is_visible_in_tree()) visible_width -= v_scroll->get_combined_minimum_size().width; - visible_width -= 20; // give it a little more space + visible_width -= 20; // Give it a little more space. if (is_wrap_enabled()) { - // center x offset + // Center x offset. int cursor_x = get_column_x_offset_for_line(cursor.column, cursor.line); if (cursor_x > (cursor.x_ofs + visible_width)) @@ -3888,7 +3877,7 @@ int TextEdit::times_line_wraps(int line) const { int wrap_amount = text.get_line_wrap_amount(line); if (wrap_amount == -1) { - // update the value + // Update the value. Vector<String> rows = get_wrap_rows_text(line); wrap_amount = rows.size() - 1; text.set_line_wrap_amount(line, wrap_amount); @@ -3928,7 +3917,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0); if (indent_ofs + word_px + w > wrap_at) { - // not enough space to add this char; start next line + // Not enough space to add this char; start next line. wrap_substring += word_str; lines.push_back(wrap_substring); cur_wrap_index++; @@ -3942,7 +3931,7 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { word_str += c; word_px += w; if (c == ' ') { - // end of a word; add this word to the substring + // End of a word; add this word to the substring. wrap_substring += word_str; px += word_px; word_str = ""; @@ -3950,9 +3939,9 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { } if (indent_ofs + px + word_px > wrap_at) { - // this word will be moved to the next line + // This word will be moved to the next line. lines.push_back(wrap_substring); - // reset for next wrap + // Reset for next wrap. cur_wrap_index++; wrap_substring = ""; px = 0; @@ -3960,11 +3949,11 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const { } col++; } - // line ends before hit wrap_at; add this word to the substring + // Line ends before hit wrap_at; add this word to the substring. wrap_substring += word_str; lines.push_back(wrap_substring); - // update cache + // Update cache. text.set_line_wrap_amount(p_line, lines.size() - 1); return lines; @@ -3982,7 +3971,7 @@ int TextEdit::get_line_wrap_index_at_col(int p_line, int p_column) const { if (!line_wraps(p_line)) return 0; - // loop through wraps in the line text until we get to the column + // Loop through wraps in the line text until we get to the column. int wrap_index = 0; int col = 0; Vector<String> rows = get_wrap_rows_text(p_line); @@ -4134,7 +4123,7 @@ void TextEdit::_scroll_moved(double p_to_val) { cursor.x_ofs = h_scroll->get_value(); if (v_scroll->is_visible_in_tree()) { - // set line ofs and wrap ofs + // Set line ofs and wrap ofs. int v_scroll_i = floor(get_v_scroll()); int sc = 0; int n_line; @@ -4289,12 +4278,12 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { _get_mouse_pos(p_pos, row, col); int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); - // breakpoint icon + // Breakpoint icon. if (draw_breakpoint_gutter && p_pos.x > left_margin - 6 && p_pos.x <= left_margin + cache.breakpoint_gutter_width - 3) { return CURSOR_POINTING_HAND; } - // info icons + // Info icons. int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.info_gutter_width; if (draw_info_gutter && p_pos.x > left_margin + cache.breakpoint_gutter_width - 6 && p_pos.x <= gutter_left - 3) { if (text.has_info_icon(row)) { @@ -4303,7 +4292,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_ARROW; } - // fold icon + // Fold icon. if (draw_fold_gutter && p_pos.x > gutter_left + cache.line_number_w - 6 && p_pos.x <= gutter_left + cache.line_number_w + cache.fold_gutter_width - 3) { if (is_folded(row) || can_fold(row)) return CURSOR_POINTING_HAND; @@ -4315,7 +4304,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { } else { int row, col; _get_mouse_pos(p_pos, row, col); - // eol fold icon + // EOL fold icon. if (is_folded(row)) { int line_width = text.get_line_width(row); line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs; @@ -4349,8 +4338,6 @@ void TextEdit::set_text(String p_text) { update(); setting_text = false; - - //get_range()->set(0); }; String TextEdit::get_text() { @@ -4377,7 +4364,7 @@ String TextEdit::get_text_for_lookup_completion() { if (i == row) { longthing += text[i].substr(0, col); - longthing += String::chr(0xFFFF); //not unicode, represents the cursor + longthing += String::chr(0xFFFF); // Not unicode, represents the cursor. longthing += text[i].substr(col, text[i].size()); } else { @@ -4399,7 +4386,7 @@ String TextEdit::get_text_for_completion() { if (i == cursor.line) { longthing += text[i].substr(0, cursor.column); - longthing += String::chr(0xFFFF); //not unicode, represents the cursor + longthing += String::chr(0xFFFF); // Not unicode, represents the cursor. longthing += text[i].substr(cursor.column, text[i].size()); } else { @@ -4587,12 +4574,12 @@ void TextEdit::_set_syntax_highlighting(SyntaxHighlighter *p_syntax_highlighter) int TextEdit::_is_line_in_region(int p_line) { - // do we have in cache? + // Do we have in cache? if (color_region_cache.has(p_line)) { return color_region_cache[p_line]; } - // if not find the closest line we have + // If not find the closest line we have. int previous_line = p_line - 1; for (; previous_line > -1; previous_line--) { if (color_region_cache.has(p_line)) { @@ -4600,7 +4587,7 @@ int TextEdit::_is_line_in_region(int p_line) { } } - // calculate up to line we need and update the cache along the way. + // Calculate up to line we need and update the cache along the way. int in_region = color_region_cache[previous_line]; if (previous_line == -1) { in_region = -1; @@ -4728,7 +4715,7 @@ void TextEdit::cut() { OS::get_singleton()->set_clipboard(clipboard); _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); - cursor_set_line(selection.from_line); // set afterwards else it causes the view to be offset + cursor_set_line(selection.from_line); // Set afterwards else it causes the view to be offset. cursor_set_column(selection.from_column); selection.active = false; @@ -4957,7 +4944,7 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc col = p_search.findn(p_key, p_from_column); } - // whole words only + // Whole words only. if (col != -1 && p_search_flags & SEARCH_WHOLE_WORDS) { p_from_column = col; @@ -4997,14 +4984,12 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l ERR_FAIL_INDEX_V(p_from_line, text.size(), false); ERR_FAIL_INDEX_V(p_from_column, text[p_from_line].length() + 1, false); - //search through the whole document, but start by current line + // Search through the whole document, but start by current line. int line = p_from_line; int pos = -1; for (int i = 0; i < text.size() + 1; i++) { - //backwards is broken... - //int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch if (line < 0) { line = text.size() - 1; @@ -5018,7 +5003,7 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l if (line == p_from_line) { if (i == text.size()) { - //wrapped + // Wrapped. if (p_search_flags & SEARCH_BACKWARDS) { from_column = text_line.length(); @@ -5066,7 +5051,7 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l bool is_match = true; if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) { - //validate for whole words + // Validate for whole words. if (pos > 0 && _is_text_char(text_line[pos - 1])) is_match = false; else if (pos + p_key.length() < text_line.length() && _is_text_char(text_line[pos + p_key.length()])) @@ -5264,7 +5249,7 @@ void TextEdit::unhide_all_lines() { int TextEdit::num_lines_from(int p_line_from, int visible_amount) const { - // returns the number of lines (hidden and unhidden) from p_line_from to (p_line_from + visible_amount of unhidden lines) + // Returns the number of lines (hidden and unhidden) from p_line_from to (p_line_from + visible_amount of unhidden lines). ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(visible_amount)); if (!is_hiding_enabled()) @@ -5297,8 +5282,8 @@ int TextEdit::num_lines_from(int p_line_from, int visible_amount) const { int TextEdit::num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const { - // returns the number of lines (hidden and unhidden) from (p_line_from + p_wrap_index_from) row to (p_line_from + visible_amount of unhidden and wrapped rows) - // wrap index is set to the wrap index of the last line + // Returns the number of lines (hidden and unhidden) from (p_line_from + p_wrap_index_from) row to (p_line_from + visible_amount of unhidden and wrapped rows). + // Wrap index is set to the wrap index of the last line. wrap_index = 0; ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(visible_amount)); @@ -5344,7 +5329,7 @@ int TextEdit::num_lines_from_rows(int p_line_from, int p_wrap_index_from, int vi int TextEdit::get_last_unhidden_line() const { - // returns the last line in the text that is not hidden + // Returns the last line in the text that is not hidden. if (!is_hiding_enabled()) return text.size() - 1; @@ -5361,7 +5346,7 @@ int TextEdit::get_indent_level(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), 0); - // counts number of tabs and spaces before line starts + // Counts number of tabs and spaces before line starts. int tab_count = 0; int whitespace_count = 0; int line_length = text[p_line].size(); @@ -5379,7 +5364,7 @@ int TextEdit::get_indent_level(int p_line) const { bool TextEdit::is_line_comment(int p_line) const { - // checks to see if this line is the start of a comment + // Checks to see if this line is the start of a comment. ERR_FAIL_INDEX_V(p_line, text.size(), false); const Map<int, Text::ColorRegionInfo> &cri_map = text.get_color_region_info(p_line); @@ -5459,7 +5444,7 @@ void TextEdit::fold_line(int p_line) { if (!can_fold(p_line)) return; - // hide lines below this one + // Hide lines below this one. int start_indent = get_indent_level(p_line); int last_line = start_indent; for (int i = p_line + 1; i < text.size(); i++) { @@ -5477,7 +5462,7 @@ void TextEdit::fold_line(int p_line) { set_line_as_hidden(i, true); } - // fix selection + // Fix selection. if (is_selection_active()) { if (is_line_hidden(selection.from_line) && is_line_hidden(selection.to_line)) { deselect(); @@ -5488,7 +5473,7 @@ void TextEdit::fold_line(int p_line) { } } - // reset cursor + // Reset cursor. if (is_line_hidden(cursor.line)) { cursor_set_line(p_line, false, false); cursor_set_column(get_line(p_line).length(), false); @@ -5549,8 +5534,8 @@ void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) { int check_line; int check_column; _base_insert_text(p_op.from_line, p_op.from_column, p_op.text, check_line, check_column); - ERR_FAIL_COND(check_line != p_op.to_line); // BUG - ERR_FAIL_COND(check_column != p_op.to_column); // BUG + ERR_FAIL_COND(check_line != p_op.to_line); // BUG. + ERR_FAIL_COND(check_column != p_op.to_column); // BUG. } else { _base_remove_text(p_op.from_line, p_op.from_column, p_op.to_line, p_op.to_column); @@ -5560,7 +5545,7 @@ void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) { void TextEdit::_clear_redo() { if (undo_stack_pos == NULL) - return; //nothing to clear + return; // Nothing to clear. _push_current_op(); @@ -5578,12 +5563,12 @@ void TextEdit::undo() { if (undo_stack_pos == NULL) { if (!undo_stack.size()) - return; //nothing to undo + return; // Nothing to undo. undo_stack_pos = undo_stack.back(); } else if (undo_stack_pos == undo_stack.front()) - return; // at the bottom of the undo stack + return; // At the bottom of the undo stack. else undo_stack_pos = undo_stack_pos->prev(); @@ -5624,7 +5609,7 @@ void TextEdit::redo() { _push_current_op(); if (undo_stack_pos == NULL) - return; //nothing to do. + return; // Nothing to do. deselect(); @@ -5678,7 +5663,7 @@ void TextEdit::end_complex_operation() { void TextEdit::_push_current_op() { if (current_op.type == TextOperation::TYPE_NONE) - return; // do nothing + return; // Nothing to do. if (next_operation_is_complex) { current_op.chain_forward = true; @@ -5778,7 +5763,7 @@ double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const { if (!is_wrap_enabled() && !is_hiding_enabled()) return p_line; - // count the number of visible lines up to this line + // Count the number of visible lines up to this line. double new_line_scroll_pos = 0; int to = CLAMP(p_line, 0, text.size() - 1); for (int i = 0; i < to; i++) { @@ -5979,7 +5964,7 @@ void TextEdit::_update_completion_candidates() { String s; - //look for keywords first + // Look for keywords first. bool inquote = false; int first_quote = -1; @@ -6004,7 +5989,7 @@ void TextEdit::_update_completion_candidates() { bool cancel = false; if (!inquote && first_quote == cofs - 1) { - //no completion here + // No completion here. cancel = true; } else if (inquote && first_quote != -1) { @@ -6042,11 +6027,12 @@ void TextEdit::_update_completion_candidates() { bool prev_is_prefix = false; if (cofs > 0 && completion_prefixes.has(String::chr(l[cofs - 1]))) prev_is_prefix = true; - if (cofs > 1 && l[cofs - 1] == ' ' && completion_prefixes.has(String::chr(l[cofs - 2]))) //check with one space before prefix, to allow indent + // Check with one space before prefix, to allow indent. + if (cofs > 1 && l[cofs - 1] == ' ' && completion_prefixes.has(String::chr(l[cofs - 2]))) prev_is_prefix = true; if (cancel || (!pre_keyword && s == "" && (cofs == 0 || !prev_is_prefix))) { - //none to complete, cancel + // None to complete, cancel. _cancel_completion(); return; } @@ -6096,18 +6082,18 @@ void TextEdit::_update_completion_candidates() { } if (completion_options.size() == 0) { - //no options to complete, cancel + // No options to complete, cancel. _cancel_completion(); return; } if (completion_options.size() == 1 && s == completion_options[0].display) { - // A perfect match, stop completion + // A perfect match, stop completion. _cancel_completion(); return; } - // The top of the list is the best match + // The top of the list is the best match. completion_current = completion_options[0]; completion_enabled = true; } @@ -6128,7 +6114,7 @@ void TextEdit::query_code_comple() { if (ofs > 0 && (inquote || _is_completable(l[ofs - 1]) || completion_prefixes.has(String::chr(l[ofs - 1])))) emit_signal("request_completion"); - else if (ofs > 1 && l[ofs - 1] == ' ' && completion_prefixes.has(String::chr(l[ofs - 2]))) //make it work with a space too, it's good enough + else if (ofs > 1 && l[ofs - 1] == ' ' && completion_prefixes.has(String::chr(l[ofs - 2]))) // Make it work with a space too, it's good enough. emit_signal("request_completion"); } @@ -6453,8 +6439,6 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_wrap_enabled", "enable"), &TextEdit::set_wrap_enabled); ClassDB::bind_method(D_METHOD("is_wrap_enabled"), &TextEdit::is_wrap_enabled); - // ClassDB::bind_method(D_METHOD("set_max_chars", "amount"), &TextEdit::set_max_chars); - // ClassDB::bind_method(D_METHOD("get_max_char"), &TextEdit::get_max_chars); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &TextEdit::set_context_menu_enabled); ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled); @@ -6546,7 +6530,6 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_enabled"), "set_wrap_enabled", "is_wrap_enabled"); - // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "max_chars"), "set_max_chars", "get_max_chars"); ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode"); @@ -6571,7 +6554,7 @@ void TextEdit::_bind_methods() { BIND_ENUM_CONSTANT(MENU_MAX); GLOBAL_DEF("gui/timers/text_edit_idle_detect_sec", 3); - ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/text_edit_idle_detect_sec", PropertyInfo(Variant::REAL, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater")); // No negative numbers + ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/text_edit_idle_detect_sec", PropertyInfo(Variant::REAL, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater")); // No negative numbers. } TextEdit::TextEdit() { @@ -6690,7 +6673,7 @@ TextEdit::TextEdit() { context_menu_enabled = true; menu = memnew(PopupMenu); add_child(menu); - readonly = true; // initialise to opposite first, so we get past the early-out in set_readonly + readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly. set_readonly(false); menu->connect("id_pressed", this, "menu_option"); first_draw = true; @@ -6751,14 +6734,14 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int bool is_symbol = _is_symbol(str[j]); bool is_number = _is_number(str[j]); - // allow ABCDEF in hex notation + // Allow ABCDEF in hex notation. if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) { is_number = true; } else { is_hex_notation = false; } - // check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation + // Check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation. if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'f' || str[j] == 'e') && !in_word && prev_is_number && !is_number) { is_number = true; is_symbol = false; @@ -6788,7 +6771,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int if (!cri.end) { in_region = cri.region; } - } else if (in_region == cri.region && !color_regions[cri.region].line_only) { //ignore otherwise + } else if (in_region == cri.region && !color_regions[cri.region].line_only) { // Ignore otherwise. if (cri.end || color_regions[cri.region].eq) { deregion = color_regions[cri.region].eq ? color_regions[cri.region].begin_key.length() : color_regions[cri.region].end_key.length(); } @@ -6816,7 +6799,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int if (col) { for (int k = j - 1; k >= 0; k--) { if (str[k] == '.') { - col = NULL; //member indexing not allowed + col = NULL; // Member indexing not allowed. break; } else if (str[k] > 32) { break; @@ -6838,7 +6821,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int k++; } - // check for space between name and bracket + // Check for space between name and bracket. while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { k++; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 0aaba5491a..0b3a193d18 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1716,14 +1716,17 @@ void Node::get_groups(List<GroupInfo> *p_groups) const { } } -bool Node::has_persistent_groups() const { +int Node::get_persistent_group_count() const { + + int count = 0; for (const Map<StringName, GroupData>::Element *E = data.grouped.front(); E; E = E->next()) { - if (E->get().persistent) - return true; + if (E->get().persistent) { + count += 1; + } } - return false; + return count; } void Node::_print_tree_pretty(const String &prefix, const bool last) { diff --git a/scene/main/node.h b/scene/main/node.h index 982bfcd620..67b40f6dfc 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -300,7 +300,7 @@ public: }; void get_groups(List<GroupInfo> *p_groups) const; - bool has_persistent_groups() const; + int get_persistent_group_count() const; void move_child(Node *p_child, int p_pos); void raise(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 6c858e9d9a..53bdb4145f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -530,6 +530,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeSwitch>(); ClassDB::register_class<VisualShaderNodeFresnel>(); ClassDB::register_class<VisualShaderNodeExpression>(); + ClassDB::register_class<VisualShaderNodeGlobalExpression>(); ClassDB::register_class<VisualShaderNodeIs>(); ClassDB::register_class<VisualShaderNodeCompare>(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 8c8552ac54..985b38f913 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2870,9 +2870,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons const Vector3 &v1 = t1.value.loc; const Vector3 &v2 = t2.value.loc; - if (Math::is_zero_approx(v0.distance_to(v2))) { + if (v0 == v2) { //0 and 2 are close, let's see if 1 is close - if (!Math::is_zero_approx(v0.distance_to(v1))) { + if (v0 != v1) { //not close, not optimizable return false; } @@ -2959,9 +2959,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons const Vector3 &v1 = t1.value.scale; const Vector3 &v2 = t2.value.scale; - if (Math::is_zero_approx(v0.distance_to(v2))) { + if (v0 == v2) { //0 and 2 are close, let's see if 1 is close - if (!Math::is_zero_approx(v0.distance_to(v1))) { + if (v0 != v1) { //not close, not optimizable return false; } diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index fb0fb4f8e3..90787780d3 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -760,6 +760,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // FileDialog theme->set_icon("folder", "FileDialog", make_icon(icon_folder_png)); + theme->set_color("folder", "FileDialog", Color(1, 1, 1)); theme->set_color("files_disabled", "FileDialog", Color(0, 0, 0, 0.7)); // colorPicker diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index df8d4a7fed..2364a4a8a3 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -193,14 +193,6 @@ Error DynamicFontAtSize::_load() { ERR_FAIL_COND_V(error, ERR_FILE_CANT_OPEN); - /*error = FT_Set_Char_Size(face,0,64*size,512,512); - - if ( error ) { - FT_Done_FreeType( library ); - ERR_EXPLAIN(TTR("Invalid font size.")); - ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); - }*/ - if (FT_HAS_COLOR(face)) { int best_match = 0; int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width)); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 389011c095..f7d7c2d1bc 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1205,6 +1205,22 @@ void VisualShader::_update_shader() const { static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" }; + String global_expressions; + for (int i = 0, index = 0; i < TYPE_MAX; i++) { + for (Map<int, Node>::Element *E = graph[i].nodes.front(); E; E = E->next()) { + Ref<VisualShaderNodeGlobalExpression> global_expression = Object::cast_to<VisualShaderNodeGlobalExpression>(E->get().node.ptr()); + if (global_expression.is_valid()) { + + String expr = ""; + expr += "// " + global_expression->get_caption() + ":" + itos(index++) + "\n"; + expr += global_expression->generate_global(get_mode(), Type(i), -1); + expr = expr.replace("\n", "\n\t"); + expr += "\n"; + global_expressions += expr; + } + } + } + for (int i = 0; i < TYPE_MAX; i++) { //make it faster to go around through shader @@ -1239,6 +1255,7 @@ void VisualShader::_update_shader() const { global_code += "\n\n"; String final_code = global_code; final_code += global_code_per_node; + final_code += global_expressions; String tcode = code; for (int i = 0; i < TYPE_MAX; i++) { tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]); @@ -1249,6 +1266,10 @@ void VisualShader::_update_shader() const { for (int i = 0; i < default_tex_params.size(); i++) { const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param); } + if (previous_code != final_code) { + const_cast<VisualShader *>(this)->emit_signal("changed"); + } + previous_code = final_code; } void VisualShader::_queue_update() { @@ -2333,6 +2354,14 @@ void VisualShaderNodeGroupBase::_apply_port_changes() { } } +void VisualShaderNodeGroupBase::set_editable(bool p_enabled) { + editable = p_enabled; +} + +bool VisualShaderNodeGroupBase::is_editable() const { + return editable; +} + void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size); @@ -2368,6 +2397,9 @@ void VisualShaderNodeGroupBase::_bind_methods() { ClassDB::bind_method(D_METHOD("set_control", "control", "index"), &VisualShaderNodeGroupBase::set_control); ClassDB::bind_method(D_METHOD("get_control", "index"), &VisualShaderNodeGroupBase::get_control); + + ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &VisualShaderNodeGroupBase::set_editable); + ClassDB::bind_method(D_METHOD("is_editable"), &VisualShaderNodeGroupBase::is_editable); } String VisualShaderNodeGroupBase::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { @@ -2378,6 +2410,7 @@ VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() { size = Size2(0, 0); inputs = ""; outputs = ""; + editable = false; } ////////////// Expression @@ -2504,4 +2537,19 @@ void VisualShaderNodeExpression::_bind_methods() { VisualShaderNodeExpression::VisualShaderNodeExpression() { expression = ""; + set_editable(true); +} + +////////////// Global Expression + +String VisualShaderNodeGlobalExpression::get_caption() const { + return "GlobalExpression"; +} + +String VisualShaderNodeGlobalExpression::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return expression; +} + +VisualShaderNodeGlobalExpression::VisualShaderNodeGlobalExpression() { + set_editable(false); } diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index a89e3295fc..45beb8e6ca 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -73,6 +73,7 @@ private: } graph[TYPE_MAX]; Shader::Mode shader_mode; + mutable String previous_code; Array _get_node_connections(Type p_type) const; @@ -371,6 +372,7 @@ protected: Vector2 size; String inputs; String outputs; + bool editable; struct Port { PortType type; @@ -426,6 +428,9 @@ public: void set_control(Control *p_control, int p_index); Control *get_control(int p_index); + void set_editable(bool p_enabled); + bool is_editable() const; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const; VisualShaderNodeGroupBase(); @@ -434,10 +439,9 @@ public: class VisualShaderNodeExpression : public VisualShaderNodeGroupBase { GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase); -private: +protected: String expression; -protected: static void _bind_methods(); public: @@ -453,4 +457,15 @@ public: VisualShaderNodeExpression(); }; +class VisualShaderNodeGlobalExpression : public VisualShaderNodeExpression { + GDCLASS(VisualShaderNodeGlobalExpression, VisualShaderNodeExpression); + +public: + virtual String get_caption() const; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const; + + VisualShaderNodeGlobalExpression(); +}; + #endif // VISUAL_SHADER_H |