diff options
270 files changed, 13720 insertions, 5521 deletions
diff --git a/.travis.yml b/.travis.yml index 133a134758..e89774a2a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -63,12 +63,10 @@ matrix: - env: GODOT_TARGET=osx TOOLS=yes CACHE_NAME=${GODOT_TARGET}-tools-clang os: osx - osx_image: xcode9.3 compiler: clang - env: GODOT_TARGET=iphone TOOLS=no CACHE_NAME=${GODOT_TARGET}-clang os: osx - osx_image: xcode9.3 compiler: clang - env: GODOT_TARGET=server TOOLS=yes CACHE_NAME=${GODOT_TARGET}-tools-gcc diff --git a/AUTHORS.md b/AUTHORS.md index d3f0592c89..e1171392d5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -77,10 +77,12 @@ name is available. Justo Delgado (mrcdk) Kelly Thomas (KellyThomas) Kostadin Damyanov (Max-Might) + K. S. Ernest (iFire) Lee (fire) Leon Krause (eska014) m4nu3lf Marcelo Fernandez (marcelofg55) Marc Gilleron (Zylann) + Marcin Zawiejski (dragmz) Mariano Javier Suligoy (MarianoGnu) Mario Schlack (hurikhan) Martin Sjursen (binbitten) @@ -18,7 +18,6 @@ generous deed immortalized in the next stable release of Godot Engine. Gamblify <https://www.gamblify.com> GameDev.TV <https://www.gamedev.tv> - Skirmish <https://skirmish.io> ## Mini sponsors @@ -26,17 +25,19 @@ generous deed immortalized in the next stable release of Godot Engine. Christian Uldall Pedersen Christopher Igoe Christoph Woinke - Claudiu Dumitru E Hewert + GameDev.net Hein-Pieter van Braam - Igors Vaitkus Jamal Alyafei Jay Sistar + Loreshaper Games Matthieu Huvé Mike King Nathan Warden Neal Gompa (Conan Kudo) Pascal Julien + Patrick Aarstad + rottis Ruslan Mustakov Sébastien Manin Slobodan Milnovic @@ -61,8 +62,7 @@ generous deed immortalized in the next stable release of Godot Engine. Allen Schade Andreas Schüle Austen McRae - Bernhard Liebl - Catalin Moldovan + David Gehrig DeepSquid Fidget Sinner Florian Breisch @@ -73,21 +73,21 @@ generous deed immortalized in the next stable release of Godot Engine. Kyle Szklenski Libre-Dépanne Matthew Bennett - Olafur Gislason Paul LaMotte Ranoller + Sergey Svenne Krap Timothy Hagberg BanjoNode2D Beliar Chris Serino + Christian Padilla Conrad Curry Craig Smith Daniel Egger David Churchill Dean Harmon - Dexter Miguel John Justo Delgado Baudà KTL @@ -98,22 +98,23 @@ generous deed immortalized in the next stable release of Godot Engine. Robin Arys Rodrigo Loli Ronnie Ashlock - Rufus Xavier Sarsaparilla ScottMakesGames Thomas Bjarnelöf - William Connell Wojciech Chojnacki + Xavier PATRICELLI Zaq Poi Alessandra Pereyra Alexey Dyadchenko Amanda Haldy + Anthony Ryan Chris Brown Chris Petrich Chris Wilson Cody Parker Corey Auger D + Deadly Lampshade E.G. Eric Eric Monson @@ -125,12 +126,13 @@ generous deed immortalized in the next stable release of Godot Engine. Guilherme Felipe de C. G. da Silva Hasen Judy Heath Hayes + Jan ÄŒejka Jay Horton Jeppe Zapp joe513 - Jordan M Lucas Juraj Móza Justin Arnold + Lars Wuethrich Leandro Voltolino Lisandro Lorea Markus Wiesner @@ -141,13 +143,14 @@ generous deed immortalized in the next stable release of Godot Engine. Pablo Cholaky Patrick Schnorbus Pete Goodwin - Phyronnaz Ruben Soares Luis + Rufus Xavier Sarsaparilla Sindre Sømme Sofox Stoned Xander Tim Dalporto Trent McPheron + Wyatt Walker ## Silver donors @@ -157,6 +160,7 @@ generous deed immortalized in the next stable release of Godot Engine. Adisibio Alder Stefano Alessandro Senese + Alexander Koppe Anders Jensen-Urstad Anthony Bongiovanni Arda Erol @@ -164,7 +168,6 @@ generous deed immortalized in the next stable release of Godot Engine. Artur Barichello Aubrey Falconer Avencherus - Bailey Bastian Böhm Benedikt Benjamin Beshara @@ -187,10 +190,11 @@ generous deed immortalized in the next stable release of Godot Engine. David David Cravens David May + Disktra Dominik Wetzel Duy Kevin Nguyen Edward Herbert - Edwin Acosta + Elias Nykrem Eric Martini Fabian Becker fengjiongmax @@ -199,6 +203,7 @@ generous deed immortalized in the next stable release of Godot Engine. Gerrit Großkopf Gerrit Procee Gilberto K. Otubo + Greg Olson Guillaume Laforte Guldoman Gumichan01 @@ -208,6 +213,7 @@ generous deed immortalized in the next stable release of Godot Engine. Ivan Vodopiviz Jahn Johansen Jaime Ruiz-Borau Vizárraga + Jake Huxell Jed Jeff Hungerford Joel Fivat @@ -217,7 +223,9 @@ generous deed immortalized in the next stable release of Godot Engine. Jonathan Martin Jonathan Nieto Jonathon + Jon Sully Josh 'Cheeseness' Bush + Juanfran Juan Negrier Judd Julian Murgia @@ -228,9 +236,11 @@ generous deed immortalized in the next stable release of Godot Engine. Klavdij Voncina Krzysztof Jankowski Linus Lind Lundgren + Luc Magitem Luis Moraes Macil magodev + Manolis Makris Martin Eigel Martins Odabi Max R.R. Collada @@ -251,12 +261,12 @@ generous deed immortalized in the next stable release of Godot Engine. Nicolas SAN AGUSTIN Niko Leopold Noi Sek - Oleg Tyshchenko Pablo Seibelt Pan Ip + Pascal Grüter Pat LaBine Patrick Nafarrete - Patric Vormstein + Paul E Hansen Paul Mason PaweÅ‚ Kowal Pierre-Igor Berthet @@ -267,21 +277,23 @@ generous deed immortalized in the next stable release of Godot Engine. Roger Burgess Roger Smith Roman Tinkov - Ryan Whited Sasori Olkof Sootstone Stefan Butucea + The K-B Theo Cranmore + Thibaud Galloy Thibault Barbaroux Thomas Bell - Thomas Hermansen Thomas Holmes Thomas Kurz + tiansheng li Tom Larrow + Tristan Crawford + Trym Nilsen Tyler Stafos UltyX Victor - Victor Gonzalez Fernandez Viktor Ferenczi waka nya werner mendizabal diff --git a/core/array.cpp b/core/array.cpp index 96e64294ed..44c553e4eb 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -259,7 +259,7 @@ Array &Array::sort_custom(Object *p_obj, const StringName &p_function) { ERR_FAIL_NULL_V(p_obj, *this); - SortArray<Variant, _ArrayVariantSortCustom> avs; + SortArray<Variant, _ArrayVariantSortCustom, true> avs; avs.compare.obj = p_obj; avs.compare.func = p_function; avs.sort(_p->array.ptrw(), _p->array.size()); diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index af1d49ae8c..26ba28370f 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -112,11 +112,22 @@ PoolStringArray _ResourceLoader::get_dependencies(const String &p_path) { return ret; }; +#ifndef DISABLE_DEPRECATED bool _ResourceLoader::has(const String &p_path) { + WARN_PRINTS("ResourceLoader.has() is deprecated, please replace it with the equivalent has_cached() or the new exists()."); + return has_cached(p_path); +} +#endif // DISABLE_DEPRECATED + +bool _ResourceLoader::has_cached(const String &p_path) { String local_path = ProjectSettings::get_singleton()->localize_path(p_path); return ResourceCache::has(local_path); -}; +} + +bool _ResourceLoader::exists(const String &p_path, const String &p_type_hint) { + return ResourceLoader::exists(p_path, p_type_hint); +} void _ResourceLoader::_bind_methods() { @@ -125,7 +136,11 @@ void _ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &_ResourceLoader::get_recognized_extensions_for_type); ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &_ResourceLoader::set_abort_on_missing_resources); ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &_ResourceLoader::get_dependencies); + ClassDB::bind_method(D_METHOD("has_cached", "path"), &_ResourceLoader::has_cached); + ClassDB::bind_method(D_METHOD("exists", "path", "type_hint"), &_ResourceLoader::exists, DEFVAL("")); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("has", "path"), &_ResourceLoader::has); +#endif // DISABLE_DEPRECATED } _ResourceLoader::_ResourceLoader() { @@ -643,7 +658,7 @@ Dictionary _OS::get_time(bool utc) const { * * @return epoch calculated */ -uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { +int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { // Bunch of conversion constants static const unsigned int SECONDS_PER_MINUTE = 60; @@ -688,13 +703,18 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { // 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; - uint64_t SECONDS_FROM_YEARS_PAST = 0; - for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { - - SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; + int64_t SECONDS_FROM_YEARS_PAST = 0; + if (year >= EPOCH_YR) { + for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { + SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; + } + } else { + for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) { + SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY; + } } - uint64_t epoch = + int64_t epoch = second + minute * SECONDS_PER_MINUTE + hour * SECONDS_PER_HOUR + @@ -717,34 +737,36 @@ uint64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { * * @return dictionary of date and time values */ -Dictionary _OS::get_datetime_from_unix_time(uint64_t unix_time_val) const { - - // Just fail if unix time is negative (when interpreted as an int). - // This means the user passed in a negative value by accident - ERR_EXPLAIN("unix_time_val was really huge!" + itos(unix_time_val) + " You probably passed in a negative value!"); - ERR_FAIL_COND_V((int64_t)unix_time_val < 0, Dictionary()); +Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { OS::Date date; OS::Time time; - unsigned long dayclock, dayno; + long dayclock, dayno; int year = EPOCH_YR; - dayclock = (unsigned long)unix_time_val % SECS_DAY; - dayno = (unsigned long)unix_time_val / SECS_DAY; + if (unix_time_val >= 0) { + dayno = unix_time_val / SECS_DAY; + dayclock = unix_time_val % SECS_DAY; + /* day 0 was a thursday */ + date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); + while (dayno >= YEARSIZE(year)) { + dayno -= YEARSIZE(year); + year++; + } + } else { + dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; + dayclock = unix_time_val - dayno * SECS_DAY; + date.weekday = static_cast<OS::Weekday>((dayno - 3) % 7 + 7); + do { + year--; + dayno += YEARSIZE(year); + } while (dayno < 0); + } time.sec = dayclock % 60; time.min = (dayclock % 3600) / 60; time.hour = dayclock / 3600; - - /* day 0 was a thursday */ - date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); - - while (dayno >= YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - date.year = year; size_t imonth = 0; diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 1729c23779..b587b9257f 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -55,7 +55,11 @@ public: PoolVector<String> get_recognized_extensions_for_type(const String &p_type); void set_abort_on_missing_resources(bool p_abort); PoolStringArray get_dependencies(const String &p_path); +#ifndef DISABLE_DEPRECATED bool has(const String &p_path); +#endif // DISABLE_DEPRECATED + bool has_cached(const String &p_path); + bool exists(const String &p_path, const String &p_type_hint = ""); _ResourceLoader(); }; @@ -266,8 +270,8 @@ public: Dictionary get_date(bool utc) const; Dictionary get_time(bool utc) const; Dictionary get_datetime(bool utc) const; - Dictionary get_datetime_from_unix_time(uint64_t unix_time_val) const; - uint64_t get_unix_time_from_datetime(Dictionary datetime) const; + Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const; + int64_t get_unix_time_from_datetime(Dictionary datetime) const; Dictionary get_time_zone_info() const; uint64_t get_unix_time() const; uint64_t get_system_time_secs() const; diff --git a/core/cowdata.h b/core/cowdata.h index 66e7d1c343..6a8f644d53 100644 --- a/core/cowdata.h +++ b/core/cowdata.h @@ -100,6 +100,7 @@ private: } void _unref(void *p_data); + void _ref(const CowData *p_from); void _ref(const CowData &p_from); void _copy_on_write(); @@ -301,6 +302,11 @@ Error CowData<T>::resize(int p_size) { } template <class T> +void CowData<T>::_ref(const CowData *p_from) { + _ref(*p_from); +} + +template <class T> void CowData<T>::_ref(const CowData &p_from) { if (_ptr == p_from._ptr) diff --git a/core/error_macros.h b/core/error_macros.h index 3587e01d54..bee738ceea 100644 --- a/core/error_macros.h +++ b/core/error_macros.h @@ -313,7 +313,7 @@ extern bool _err_error_exists; #define WARN_DEPRECATED \ { \ - static bool warning_shown = false; \ + static volatile bool warning_shown = false; \ if (!warning_shown) { \ _err_print_error(FUNCTION_STR, __FILE__, __LINE__, "This method has been deprecated and will be removed in the future", ERR_HANDLER_WARNING); \ _err_error_exists = false; \ diff --git a/core/image.cpp b/core/image.cpp index 19440d1718..c94f2c3534 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -36,8 +36,8 @@ #include "math_funcs.h" #include "print_string.h" +#include "io/resource_loader.h" #include "thirdparty/misc/hq2x.h" - #include <stdio.h> const char *Image::format_names[Image::FORMAT_MAX] = { @@ -987,8 +987,10 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & int pixsize = get_format_pixel_size(p_format); int pixshift = get_format_pixel_rshift(p_format); int block = get_format_block_size(p_format); - int minw, minh; - get_format_min_pixel_size(p_format, minw, minh); + //technically, you can still compress up to 1 px no matter the format, so commenting this + //int minw, minh; + //get_format_min_pixel_size(p_format, minw, minh); + int minw = 1, minh = 1; while (true) { @@ -1304,7 +1306,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma 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) + " in Image::create()"); + 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); } @@ -1580,7 +1582,11 @@ Image::AlphaMode Image::detect_alpha() const { } Error Image::load(const String &p_path) { - +#ifdef DEBUG_ENABLED + if (p_path.begins_with("res://") && ResourceLoader::exists(p_path)) { + WARN_PRINTS("Loaded resource as image file, this will not work on export: '" + p_path + "'. Instead, import the image file as an Image resource and load it normally as a resource."); + } +#endif return ImageLoader::load_image(p_path, this); } @@ -1592,10 +1598,10 @@ Error Image::save_png(const String &p_path) const { return save_png_func(p_path, Ref<Image>((Image *)this)); } -int Image::get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps) { +int Image::get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps) { int mm; - return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps); + return _get_dst_image_size(p_width, p_height, p_format, mm, p_mipmaps ? -1 : 0); } int Image::get_image_required_mipmaps(int p_width, int p_height, Format p_format) { @@ -2376,6 +2382,17 @@ Image::DetectChannels Image::get_detected_channels() { return DETECTED_RGBA; } +void Image::optimize_channels() { + switch (get_detected_channels()) { + case DETECTED_L: convert(FORMAT_L8); break; + case DETECTED_LA: convert(FORMAT_LA8); break; + case DETECTED_R: convert(FORMAT_R8); break; + case DETECTED_RG: convert(FORMAT_RG8); break; + case DETECTED_RGB: convert(FORMAT_RGB8); break; + case DETECTED_RGBA: convert(FORMAT_RGBA8); break; + } +} + void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("get_width"), &Image::get_width); diff --git a/core/image.h b/core/image.h index 8c4854e053..c8dd647c31 100644 --- a/core/image.h +++ b/core/image.h @@ -116,7 +116,8 @@ public: enum CompressSource { COMPRESS_SOURCE_GENERIC, COMPRESS_SOURCE_SRGB, - COMPRESS_SOURCE_NORMAL + COMPRESS_SOURCE_NORMAL, + COMPRESS_SOURCE_LAYERED, }; //some functions provided by something else @@ -272,7 +273,7 @@ public: static int get_format_block_size(Format p_format); static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h); - static int get_image_data_size(int p_width, int p_height, Format p_format, int p_mipmaps = 0); + static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false); static int get_image_required_mipmaps(int p_width, int p_height, Format p_format); enum CompressMode { @@ -329,6 +330,7 @@ public: }; DetectChannels get_detected_channels(); + void optimize_channels(); Color get_pixelv(const Point2 &p_src) const; Color get_pixel(int p_x, int p_y) const; diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 614fbb771f..b8fd13d67c 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -185,5 +185,5 @@ bool ResourceFormatLoaderImage::handles_type(const String &p_type) const { String ResourceFormatLoaderImage::get_resource_type(const String &p_path) const { - return "Image"; + return p_path.get_extension().to_lower() == "image" ? "Image" : String(); } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index c44d2597a7..8b0655deb0 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -123,6 +123,10 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const Stri return ril; } +bool ResourceFormatLoader::exists(const String &p_path) const { + return FileAccess::exists(p_path); //by default just check file +} + RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error) { String path = p_path; @@ -239,6 +243,36 @@ RES ResourceLoader::load(const String &p_path, const String &p_type_hint, bool p return res; } +bool ResourceLoader::exists(const String &p_path, const String &p_type_hint) { + + String local_path; + if (p_path.is_rel_path()) + local_path = "res://" + p_path; + else + local_path = ProjectSettings::get_singleton()->localize_path(p_path); + + if (ResourceCache::has(local_path)) { + + return true; // If cached, it probably exists + } + + bool xl_remapped = false; + String path = _path_remap(local_path, &xl_remapped); + + // Try all loaders and pick the first match for the type hint + for (int i = 0; i < loader_count; i++) { + + if (!loader[i]->recognize_path(path, p_type_hint)) { + continue; + } + + if (loader[i]->exists(path)) + return true; + } + + return false; +} + Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path, const String &p_type_hint, bool p_no_cache, Error *r_error) { if (r_error) diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 9be82abb42..f78464ef0c 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -60,6 +60,7 @@ class ResourceFormatLoader { public: virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual bool exists(const String &p_path) const; virtual void get_recognized_extensions(List<String> *p_extensions) const = 0; virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; @@ -106,6 +107,7 @@ class ResourceLoader { public: static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); static RES load(const String &p_path, const String &p_type_hint = "", bool p_no_cache = false, Error *r_error = NULL); + static bool exists(const String &p_path, const String &p_type_hint = ""); static void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions); static void add_resource_format_loader(ResourceFormatLoader *p_format_loader, bool p_at_front = false); diff --git a/core/math/expression.cpp b/core/math/expression.cpp new file mode 100644 index 0000000000..a161dbddba --- /dev/null +++ b/core/math/expression.cpp @@ -0,0 +1,2136 @@ +#include "expression.h" + +#include "class_db.h" +#include "func_ref.h" +#include "io/marshalls.h" +#include "math_funcs.h" +#include "os/os.h" +#include "reference.h" +#include "variant_parser.h" + +const char *Expression::func_name[Expression::FUNC_MAX] = { + "sin", + "cos", + "tan", + "sinh", + "cosh", + "tanh", + "asin", + "acos", + "atan", + "atan2", + "sqrt", + "fmod", + "fposmod", + "floor", + "ceil", + "round", + "abs", + "sign", + "pow", + "log", + "exp", + "is_nan", + "is_inf", + "ease", + "decimals", + "stepify", + "lerp", + "inverse_lerp", + "range_lerp", + "dectime", + "randomize", + "randi", + "randf", + "rand_range", + "seed", + "rand_seed", + "deg2rad", + "rad2deg", + "linear2db", + "db2linear", + "polar2cartesian", + "cartesian2polar", + "wrapi", + "wrapf", + "max", + "min", + "clamp", + "nearest_po2", + "weakref", + "funcref", + "convert", + "typeof", + "type_exists", + "char", + "str", + "print", + "printerr", + "printraw", + "var2str", + "str2var", + "var2bytes", + "bytes2var", + "color_named", +}; + +Expression::BuiltinFunc Expression::find_function(const String &p_string) { + + for (int i = 0; i < FUNC_MAX; i++) { + if (p_string == func_name[i]) + return BuiltinFunc(i); + } + + return FUNC_MAX; +} + +String Expression::get_func_name(BuiltinFunc p_func) { + + ERR_FAIL_INDEX_V(p_func, FUNC_MAX, String()); + return func_name[p_func]; +} + +int Expression::get_func_argument_count(BuiltinFunc p_func) { + + switch (p_func) { + + case MATH_RANDOMIZE: + case MATH_RAND: + case MATH_RANDF: + return 0; + case MATH_SIN: + case MATH_COS: + case MATH_TAN: + case MATH_SINH: + case MATH_COSH: + case MATH_TANH: + case MATH_ASIN: + case MATH_ACOS: + case MATH_ATAN: + case MATH_SQRT: + case MATH_FLOOR: + case MATH_CEIL: + case MATH_ROUND: + case MATH_ABS: + case MATH_SIGN: + case MATH_LOG: + case MATH_EXP: + case MATH_ISNAN: + case MATH_ISINF: + case MATH_DECIMALS: + case MATH_SEED: + case MATH_RANDSEED: + case MATH_DEG2RAD: + case MATH_RAD2DEG: + case MATH_LINEAR2DB: + case MATH_DB2LINEAR: + case LOGIC_NEAREST_PO2: + case OBJ_WEAKREF: + case TYPE_OF: + case TEXT_CHAR: + case TEXT_STR: + case TEXT_PRINT: + case TEXT_PRINTERR: + case TEXT_PRINTRAW: + case VAR_TO_STR: + case STR_TO_VAR: + case VAR_TO_BYTES: + case BYTES_TO_VAR: + case TYPE_EXISTS: + return 1; + case MATH_ATAN2: + case MATH_FMOD: + case MATH_FPOSMOD: + case MATH_POW: + case MATH_EASE: + case MATH_STEPIFY: + case MATH_RANDOM: + case MATH_POLAR2CARTESIAN: + case MATH_CARTESIAN2POLAR: + case LOGIC_MAX: + case LOGIC_MIN: + case FUNC_FUNCREF: + case TYPE_CONVERT: + case COLORN: + return 2; + case MATH_LERP: + case MATH_INVERSE_LERP: + case MATH_DECTIME: + case MATH_WRAP: + case MATH_WRAPF: + case LOGIC_CLAMP: + return 3; + case MATH_RANGE_LERP: + return 5; + case FUNC_MAX: { + } + } + return 0; +} + +#define VALIDATE_ARG_NUM(m_arg) \ + if (!p_inputs[m_arg]->is_num()) { \ + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; \ + r_error.argument = m_arg; \ + r_error.expected = Variant::REAL; \ + return; \ + } + +void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str) { + + switch (p_func) { + case MATH_SIN: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::sin((double)*p_inputs[0]); + } break; + case MATH_COS: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::cos((double)*p_inputs[0]); + } break; + case MATH_TAN: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::tan((double)*p_inputs[0]); + } break; + case MATH_SINH: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::sinh((double)*p_inputs[0]); + } break; + case MATH_COSH: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::cosh((double)*p_inputs[0]); + } break; + case MATH_TANH: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::tanh((double)*p_inputs[0]); + } break; + case MATH_ASIN: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::asin((double)*p_inputs[0]); + } break; + case MATH_ACOS: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::acos((double)*p_inputs[0]); + } break; + case MATH_ATAN: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::atan((double)*p_inputs[0]); + } break; + case MATH_ATAN2: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::atan2((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_SQRT: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::sqrt((double)*p_inputs[0]); + } break; + case MATH_FMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::fmod((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_FPOSMOD: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_FLOOR: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::floor((double)*p_inputs[0]); + } break; + case MATH_CEIL: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::ceil((double)*p_inputs[0]); + } break; + case MATH_ROUND: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::round((double)*p_inputs[0]); + } break; + case MATH_ABS: { + + if (p_inputs[0]->get_type() == Variant::INT) { + + int64_t i = *p_inputs[0]; + *r_return = ABS(i); + } else if (p_inputs[0]->get_type() == Variant::REAL) { + + real_t r = *p_inputs[0]; + *r_return = Math::abs(r); + } else { + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::REAL; + } + } break; + case MATH_SIGN: { + + if (p_inputs[0]->get_type() == Variant::INT) { + + int64_t i = *p_inputs[0]; + *r_return = i < 0 ? -1 : (i > 0 ? +1 : 0); + } else if (p_inputs[0]->get_type() == Variant::REAL) { + + real_t r = *p_inputs[0]; + *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0); + } else { + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::REAL; + } + } break; + case MATH_POW: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::pow((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_LOG: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::log((double)*p_inputs[0]); + } break; + case MATH_EXP: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::exp((double)*p_inputs[0]); + } break; + case MATH_ISNAN: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::is_nan((double)*p_inputs[0]); + } break; + case MATH_ISINF: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::is_inf((double)*p_inputs[0]); + } break; + case MATH_EASE: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::ease((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_DECIMALS: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::step_decimals((double)*p_inputs[0]); + } break; + case MATH_STEPIFY: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::stepify((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; + case MATH_INVERSE_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; + case MATH_RANGE_LERP: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + VALIDATE_ARG_NUM(3); + VALIDATE_ARG_NUM(4); + *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]); + } break; + case MATH_DECTIME: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::dectime((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; + case MATH_RANDOMIZE: { + Math::randomize(); + + } break; + case MATH_RAND: { + *r_return = Math::rand(); + } break; + case MATH_RANDF: { + *r_return = Math::randf(); + } break; + case MATH_RANDOM: { + + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + *r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]); + } break; + case MATH_SEED: { + + VALIDATE_ARG_NUM(0); + uint64_t seed = *p_inputs[0]; + Math::seed(seed); + + } break; + case MATH_RANDSEED: { + + VALIDATE_ARG_NUM(0); + uint64_t seed = *p_inputs[0]; + int ret = Math::rand_from_seed(&seed); + Array reta; + reta.push_back(ret); + reta.push_back(seed); + *r_return = reta; + + } break; + case MATH_DEG2RAD: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::deg2rad((double)*p_inputs[0]); + } break; + case MATH_RAD2DEG: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::rad2deg((double)*p_inputs[0]); + } break; + case MATH_LINEAR2DB: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::linear2db((double)*p_inputs[0]); + } break; + case MATH_DB2LINEAR: { + + VALIDATE_ARG_NUM(0); + *r_return = Math::db2linear((double)*p_inputs[0]); + } break; + case MATH_POLAR2CARTESIAN: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + double r = *p_inputs[0]; + double th = *p_inputs[1]; + *r_return = Vector2(r * Math::cos(th), r * Math::sin(th)); + } break; + case MATH_CARTESIAN2POLAR: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + double x = *p_inputs[0]; + double y = *p_inputs[1]; + *r_return = Vector2(Math::sqrt(x * x + y * y), Math::atan2(y, x)); + } break; + case MATH_WRAP: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]); + } break; + case MATH_WRAPF: { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]); + } break; + case LOGIC_MAX: { + + if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *r_return = MAX(a, b); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + + *r_return = MAX(a, b); + } + + } break; + case LOGIC_MIN: { + + if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + *r_return = MIN(a, b); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + + *r_return = MIN(a, b); + } + } break; + case LOGIC_CLAMP: { + + if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT && p_inputs[2]->get_type() == Variant::INT) { + + int64_t a = *p_inputs[0]; + int64_t b = *p_inputs[1]; + int64_t c = *p_inputs[2]; + *r_return = CLAMP(a, b, c); + } else { + VALIDATE_ARG_NUM(0); + VALIDATE_ARG_NUM(1); + VALIDATE_ARG_NUM(2); + + real_t a = *p_inputs[0]; + real_t b = *p_inputs[1]; + real_t c = *p_inputs[2]; + + *r_return = CLAMP(a, b, c); + } + } break; + case LOGIC_NEAREST_PO2: { + + VALIDATE_ARG_NUM(0); + int64_t num = *p_inputs[0]; + *r_return = next_power_of_2(num); + } break; + case OBJ_WEAKREF: { + + if (p_inputs[0]->get_type() != Variant::OBJECT) { + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + + return; + } + + if (p_inputs[0]->is_ref()) { + + REF r = *p_inputs[0]; + if (!r.is_valid()) { + + return; + } + + Ref<WeakRef> wref = memnew(WeakRef); + wref->set_ref(r); + *r_return = wref; + } else { + Object *obj = *p_inputs[0]; + if (!obj) { + + return; + } + Ref<WeakRef> wref = memnew(WeakRef); + wref->set_obj(obj); + *r_return = wref; + } + + } break; + case FUNC_FUNCREF: { + + if (p_inputs[0]->get_type() != Variant::OBJECT) { + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + + return; + } + if (p_inputs[1]->get_type() != Variant::STRING && p_inputs[1]->get_type() != Variant::NODE_PATH) { + + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING; + + return; + } + + Ref<FuncRef> fr = memnew(FuncRef); + + fr->set_instance(*p_inputs[0]); + fr->set_function(*p_inputs[1]); + + *r_return = fr; + + } break; + case TYPE_CONVERT: { + + VALIDATE_ARG_NUM(1); + int type = *p_inputs[1]; + if (type < 0 || type >= Variant::VARIANT_MAX) { + + r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants."); + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::INT; + return; + + } else { + + *r_return = Variant::construct(Variant::Type(type), p_inputs, 1, r_error); + } + } break; + case TYPE_OF: { + + *r_return = p_inputs[0]->get_type(); + + } break; + case TYPE_EXISTS: { + + *r_return = ClassDB::class_exists(*p_inputs[0]); + + } break; + case TEXT_CHAR: { + + CharType result[2] = { *p_inputs[0], 0 }; + + *r_return = String(result); + + } break; + case TEXT_STR: { + + String str = *p_inputs[0]; + + *r_return = str; + + } break; + case TEXT_PRINT: { + + String str = *p_inputs[0]; + print_line(str); + + } break; + + case TEXT_PRINTERR: { + + String str = *p_inputs[0]; + + //str+="\n"; + print_error(str); + + } break; + case TEXT_PRINTRAW: { + String str = *p_inputs[0]; + + //str+="\n"; + OS::get_singleton()->print("%s", str.utf8().get_data()); + + } break; + case VAR_TO_STR: { + + String vars; + VariantWriter::write_to_string(*p_inputs[0], vars); + *r_return = vars; + } break; + case STR_TO_VAR: { + + if (p_inputs[0]->get_type() != Variant::STRING) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::STRING; + + return; + } + + VariantParser::StreamString ss; + ss.s = *p_inputs[0]; + + String errs; + int line; + Error err = VariantParser::parse(&ss, *r_return, errs, line); + + if (err != OK) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::STRING; + *r_return = "Parse error at line " + itos(line) + ": " + errs; + return; + } + + } break; + case VAR_TO_BYTES: { + + PoolByteArray barr; + int len; + Error err = encode_variant(*p_inputs[0], NULL, len); + if (err) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::NIL; + r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID)."; + return; + } + + barr.resize(len); + { + PoolByteArray::Write w = barr.write(); + encode_variant(*p_inputs[0], w.ptr(), len); + } + *r_return = barr; + } break; + case BYTES_TO_VAR: { + + if (p_inputs[0]->get_type() != Variant::POOL_BYTE_ARRAY) { + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::POOL_BYTE_ARRAY; + + return; + } + + PoolByteArray varr = *p_inputs[0]; + Variant ret; + { + PoolByteArray::Read r = varr.read(); + Error err = decode_variant(ret, r.ptr(), varr.size(), NULL); + if (err != OK) { + r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format."); + r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::POOL_BYTE_ARRAY; + return; + } + } + + *r_return = ret; + + } break; + case COLORN: { + + VALIDATE_ARG_NUM(1); + + Color color = Color::named(*p_inputs[0]); + color.a = *p_inputs[1]; + + *r_return = String(color); + + } break; + default: {} + } +} + +//////// + +Error Expression::_get_token(Token &r_token) { + + while (true) { +#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++]) + + CharType cchar = GET_CHAR(); + if (cchar == 0) { + r_token.type = TK_EOF; + return OK; + } + + switch (cchar) { + + case 0: { + r_token.type = TK_EOF; + return OK; + } break; + case '{': { + + r_token.type = TK_CURLY_BRACKET_OPEN; + return OK; + }; + case '}': { + + r_token.type = TK_CURLY_BRACKET_CLOSE; + return OK; + }; + case '[': { + + r_token.type = TK_BRACKET_OPEN; + return OK; + }; + case ']': { + + r_token.type = TK_BRACKET_CLOSE; + return OK; + }; + case '(': { + + r_token.type = TK_PARENTHESIS_OPEN; + return OK; + }; + case ')': { + + r_token.type = TK_PARENTHESIS_CLOSE; + return OK; + }; + case ',': { + + r_token.type = TK_COMMA; + return OK; + }; + case ':': { + + r_token.type = TK_COLON; + return OK; + }; + case '.': { + + r_token.type = TK_PERIOD; + return OK; + }; + case '$': { + + r_token.type = TK_INPUT; + int index = 0; + do { + if (expression[str_ofs] < '0' || expression[str_ofs] > '9') { + _set_error("Expected number after '$'"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + index *= 10; + index += expression[str_ofs] - '0'; + str_ofs++; + + } while (expression[str_ofs] >= '0' && expression[str_ofs] <= '9'); + + r_token.value = index; + return OK; + }; + case '=': { + + cchar = GET_CHAR(); + if (cchar == '=') { + r_token.type = TK_OP_EQUAL; + } else { + _set_error("Expected '='"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + return OK; + }; + case '!': { + + if (expression[str_ofs] == '=') { + r_token.type = TK_OP_NOT_EQUAL; + str_ofs++; + } else { + r_token.type = TK_OP_NOT; + } + return OK; + }; + case '>': { + + if (expression[str_ofs] == '=') { + r_token.type = TK_OP_GREATER_EQUAL; + str_ofs++; + } else if (expression[str_ofs] == '>') { + r_token.type = TK_OP_SHIFT_RIGHT; + str_ofs++; + } else { + r_token.type = TK_OP_GREATER; + } + return OK; + }; + case '<': { + + if (expression[str_ofs] == '=') { + r_token.type = TK_OP_LESS_EQUAL; + str_ofs++; + } else if (expression[str_ofs] == '<') { + r_token.type = TK_OP_SHIFT_LEFT; + str_ofs++; + } else { + r_token.type = TK_OP_LESS; + } + return OK; + }; + case '+': { + r_token.type = TK_OP_ADD; + return OK; + }; + case '-': { + r_token.type = TK_OP_SUB; + return OK; + }; + case '/': { + r_token.type = TK_OP_DIV; + return OK; + }; + case '*': { + r_token.type = TK_OP_MUL; + return OK; + }; + case '%': { + r_token.type = TK_OP_MOD; + return OK; + }; + case '&': { + + if (expression[str_ofs] == '&') { + r_token.type = TK_OP_AND; + str_ofs++; + } else { + r_token.type = TK_OP_BIT_AND; + } + return OK; + }; + case '|': { + + if (expression[str_ofs] == '|') { + r_token.type = TK_OP_OR; + str_ofs++; + } else { + r_token.type = TK_OP_BIT_OR; + } + return OK; + }; + case '^': { + + r_token.type = TK_OP_BIT_XOR; + + return OK; + }; + case '~': { + + r_token.type = TK_OP_BIT_INVERT; + + return OK; + }; + case '"': { + + String str; + while (true) { + + CharType ch = GET_CHAR(); + + if (ch == 0) { + _set_error("Unterminated String"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } else if (ch == '"') { + break; + } else if (ch == '\\') { + //escaped characters... + + CharType next = GET_CHAR(); + if (next == 0) { + _set_error("Unterminated String"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + CharType res = 0; + + switch (next) { + + case 'b': res = 8; break; + case 't': res = 9; break; + case 'n': res = 10; break; + case 'f': res = 12; break; + case 'r': res = 13; break; + case 'u': { + //hexnumbarh - oct is deprecated + + for (int j = 0; j < 4; j++) { + CharType c = GET_CHAR(); + + if (c == 0) { + _set_error("Unterminated String"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { + + _set_error("Malformed hex constant in string"); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + CharType v; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (c >= 'a' && c <= 'f') { + v = c - 'a'; + v += 10; + } else if (c >= 'A' && c <= 'F') { + v = c - 'A'; + v += 10; + } else { + ERR_PRINT("BUG"); + v = 0; + } + + res <<= 4; + res |= v; + } + + } break; + //case '\"': res='\"'; break; + //case '\\': res='\\'; break; + //case '/': res='/'; break; + default: { + res = next; + //r_err_str="Invalid escape sequence"; + //return ERR_PARSE_ERROR; + } break; + } + + str += res; + + } else { + str += ch; + } + } + + r_token.type = TK_CONSTANT; + r_token.value = str; + return OK; + + } break; + default: { + + if (cchar <= 32) { + break; + } + + if (cchar >= '0' && cchar <= '9') { + //a number + + String num; +#define READING_SIGN 0 +#define READING_INT 1 +#define READING_DEC 2 +#define READING_EXP 3 +#define READING_DONE 4 + int reading = READING_INT; + + CharType c = cchar; + bool exp_sign = false; + bool exp_beg = false; + bool is_float = false; + + while (true) { + + switch (reading) { + case READING_INT: { + + if (c >= '0' && c <= '9') { + //pass + } else if (c == '.') { + reading = READING_DEC; + is_float = true; + } else if (c == 'e') { + reading = READING_EXP; + } else { + reading = READING_DONE; + } + + } break; + case READING_DEC: { + + if (c >= '0' && c <= '9') { + + } else if (c == 'e') { + reading = READING_EXP; + + } else { + reading = READING_DONE; + } + + } break; + case READING_EXP: { + + if (c >= '0' && c <= '9') { + exp_beg = true; + + } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) { + if (c == '-') + is_float = true; + exp_sign = true; + + } else { + reading = READING_DONE; + } + } break; + } + + if (reading == READING_DONE) + break; + num += String::chr(c); + c = GET_CHAR(); + } + + str_ofs--; + + r_token.type = TK_CONSTANT; + + if (is_float) + r_token.value = num.to_double(); + else + r_token.value = num.to_int(); + return OK; + + } else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') { + + String id; + bool first = true; + + while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) { + + id += String::chr(cchar); + cchar = GET_CHAR(); + first = false; + } + + str_ofs--; //go back one + + if (id == "in") { + r_token.type = TK_OP_IN; + } else if (id == "null") { + r_token.type = TK_CONSTANT; + r_token.value = Variant(); + } else if (id == "true") { + r_token.type = TK_CONSTANT; + r_token.value = true; + } else if (id == "false") { + r_token.type = TK_CONSTANT; + r_token.value = false; + } else if (id == "PI") { + r_token.type = TK_CONSTANT; + r_token.value = Math_PI; + } else if (id == "TAU") { + r_token.type = TK_CONSTANT; + r_token.value = Math_TAU; + } else if (id == "INF") { + r_token.type = TK_CONSTANT; + r_token.value = Math_INF; + } else if (id == "NAN") { + r_token.type = TK_CONSTANT; + r_token.value = Math_NAN; + } else if (id == "not") { + r_token.type = TK_OP_NOT; + } else if (id == "or") { + r_token.type = TK_OP_OR; + } else if (id == "and") { + r_token.type = TK_OP_AND; + } else if (id == "self") { + r_token.type = TK_SELF; + } else { + + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (id == Variant::get_type_name(Variant::Type(i))) { + r_token.type = TK_BASIC_TYPE; + r_token.value = i; + return OK; + } + } + + BuiltinFunc bifunc = find_function(id); + if (bifunc != FUNC_MAX) { + r_token.type = TK_BUILTIN_FUNC; + r_token.value = bifunc; + return OK; + } + + r_token.type = TK_IDENTIFIER; + r_token.value = id; + } + + return OK; + } else { + _set_error("Unexpected character."); + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; + } + } + } + } + + r_token.type = TK_ERROR; + return ERR_PARSE_ERROR; +} + +const char *Expression::token_name[TK_MAX] = { + "CURLY BRACKET OPEN", + "CURLY BRACKET CLOSE", + "BRACKET OPEN", + "BRACKET CLOSE", + "PARENTHESIS OPEN", + "PARENTHESIS CLOSE", + "IDENTIFIER", + "BUILTIN FUNC", + "SELF", + "CONSTANT", + "BASIC TYPE", + "COLON", + "COMMA", + "PERIOD", + "OP IN", + "OP EQUAL", + "OP NOT EQUAL", + "OP LESS", + "OP LESS EQUAL", + "OP GREATER", + "OP GREATER EQUAL", + "OP AND", + "OP OR", + "OP NOT", + "OP ADD", + "OP SUB", + "OP MUL", + "OP DIV", + "OP MOD", + "OP SHIFT LEFT", + "OP SHIFT RIGHT", + "OP BIT AND", + "OP BIT OR", + "OP BIT XOR", + "OP BIT INVERT", + "OP INPUT", + "EOF", + "ERROR" +}; + +Expression::ENode *Expression::_parse_expression() { + + Vector<ExpressionNode> expression; + + while (true) { + //keep appending stuff to expression + ENode *expr = NULL; + + Token tk; + _get_token(tk); + if (error_set) + return NULL; + + switch (tk.type) { + case TK_CURLY_BRACKET_OPEN: { + //a dictionary + DictionaryNode *dn = alloc_node<DictionaryNode>(); + + while (true) { + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_CURLY_BRACKET_CLOSE) { + break; + } + str_ofs = cofs; //revert + //parse an expression + ENode *expr = _parse_expression(); + if (!expr) + return NULL; + dn->dict.push_back(expr); + + _get_token(tk); + if (tk.type != TK_COLON) { + _set_error("Expected ':'"); + return NULL; + } + + expr = _parse_expression(); + if (!expr) + return NULL; + + dn->dict.push_back(expr); + + cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_COMMA) { + //all good + } else if (tk.type == TK_CURLY_BRACKET_CLOSE) { + str_ofs = cofs; + } else { + _set_error("Expected ',' or '}'"); + } + } + + expr = dn; + } break; + case TK_BRACKET_OPEN: { + //an array + + ArrayNode *an = alloc_node<ArrayNode>(); + + while (true) { + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_BRACKET_CLOSE) { + break; + } + str_ofs = cofs; //revert + //parse an expression + ENode *expr = _parse_expression(); + if (!expr) + return NULL; + an->array.push_back(expr); + + cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_COMMA) { + //all good + } else if (tk.type == TK_BRACKET_CLOSE) { + str_ofs = cofs; + } else { + _set_error("Expected ',' or ']'"); + } + } + + expr = an; + } break; + case TK_PARENTHESIS_OPEN: { + //a suexpression + ENode *e = _parse_expression(); + if (error_set) + return NULL; + _get_token(tk); + if (tk.type != TK_PARENTHESIS_CLOSE) { + _set_error("Expected ')'"); + return NULL; + } + + expr = e; + + } break; + case TK_IDENTIFIER: { + + String identifier = tk.value; + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_PARENTHESIS_OPEN) { + //function call + CallNode *func_call = alloc_node<CallNode>(); + func_call->method = identifier; + SelfNode *self_node = alloc_node<SelfNode>(); + func_call->base = self_node; + + while (true) { + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs = cofs; //revert + //parse an expression + ENode *expr = _parse_expression(); + if (!expr) + return NULL; + + func_call->arguments.push_back(expr); + + cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_COMMA) { + //all good + } else if (tk.type == TK_PARENTHESIS_CLOSE) { + str_ofs = cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + expr = func_call; + } else { + //named indexing + str_ofs = cofs; + + int input_index = -1; + for (int i = 0; i < input_names.size(); i++) { + if (input_names[i] == identifier) { + input_index = i; + break; + } + } + + if (input_index != -1) { + InputNode *input = alloc_node<InputNode>(); + input->index = input_index; + expr = input; + } else { + + NamedIndexNode *index = alloc_node<NamedIndexNode>(); + SelfNode *self_node = alloc_node<SelfNode>(); + index->base = self_node; + index->name = identifier; + expr = index; + } + } + } break; + case TK_INPUT: { + + InputNode *input = alloc_node<InputNode>(); + input->index = tk.value; + expr = input; + } break; + case TK_SELF: { + + SelfNode *self = alloc_node<SelfNode>(); + expr = self; + } break; + case TK_CONSTANT: { + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value = tk.value; + expr = constant; + } break; + case TK_BASIC_TYPE: { + //constructor.. + + Variant::Type bt = Variant::Type(int(tk.value)); + _get_token(tk); + if (tk.type != TK_PARENTHESIS_OPEN) { + _set_error("Expected '('"); + return NULL; + } + + ConstructorNode *constructor = alloc_node<ConstructorNode>(); + constructor->data_type = bt; + + while (true) { + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs = cofs; //revert + //parse an expression + ENode *expr = _parse_expression(); + if (!expr) + return NULL; + + constructor->arguments.push_back(expr); + + cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_COMMA) { + //all good + } else if (tk.type == TK_PARENTHESIS_CLOSE) { + str_ofs = cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + expr = constructor; + + } break; + case TK_BUILTIN_FUNC: { + //builtin function + + _get_token(tk); + if (tk.type != TK_PARENTHESIS_OPEN) { + _set_error("Expected '('"); + return NULL; + } + + BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>(); + bifunc->func = BuiltinFunc(int(tk.value)); + + while (true) { + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs = cofs; //revert + //parse an expression + ENode *expr = _parse_expression(); + if (!expr) + return NULL; + + bifunc->arguments.push_back(expr); + + cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_COMMA) { + //all good + } else if (tk.type == TK_PARENTHESIS_CLOSE) { + str_ofs = cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + int expected_args = get_func_argument_count(bifunc->func); + if (bifunc->arguments.size() != expected_args) { + _set_error("Builtin func '" + get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments."); + } + + expr = bifunc; + + } break; + case TK_OP_SUB: { + + ExpressionNode e; + e.is_op = true; + e.op = Variant::OP_NEGATE; + expression.push_back(e); + continue; + } break; + case TK_OP_NOT: { + + ExpressionNode e; + e.is_op = true; + e.op = Variant::OP_NOT; + expression.push_back(e); + continue; + } break; + + default: { + _set_error("Expected expression."); + return NULL; + } break; + } + + //before going to operators, must check indexing! + + while (true) { + int cofs2 = str_ofs; + _get_token(tk); + if (error_set) + return NULL; + + bool done = false; + + switch (tk.type) { + case TK_BRACKET_OPEN: { + //value indexing + + IndexNode *index = alloc_node<IndexNode>(); + index->base = expr; + + ENode *what = _parse_expression(); + if (!what) + return NULL; + + index->index = what; + + _get_token(tk); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']' at end of index."); + return NULL; + } + expr = index; + + } break; + case TK_PERIOD: { + //named indexing or function call + _get_token(tk); + if (tk.type != TK_IDENTIFIER) { + _set_error("Expected identifier after '.'"); + return NULL; + } + + StringName identifier = tk.value; + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_PARENTHESIS_OPEN) { + //function call + CallNode *func_call = alloc_node<CallNode>(); + func_call->method = identifier; + func_call->base = expr; + + while (true) { + + int cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_PARENTHESIS_CLOSE) { + break; + } + str_ofs = cofs; //revert + //parse an expression + ENode *expr = _parse_expression(); + if (!expr) + return NULL; + + func_call->arguments.push_back(expr); + + cofs = str_ofs; + _get_token(tk); + if (tk.type == TK_COMMA) { + //all good + } else if (tk.type == TK_PARENTHESIS_CLOSE) { + str_ofs = cofs; + } else { + _set_error("Expected ',' or ')'"); + } + } + + expr = func_call; + } else { + //named indexing + str_ofs = cofs; + + NamedIndexNode *index = alloc_node<NamedIndexNode>(); + index->base = expr; + index->name = identifier; + expr = index; + } + + } break; + default: { + str_ofs = cofs2; + done = true; + } break; + } + + if (done) + break; + } + + //push expression + { + ExpressionNode e; + e.is_op = false; + e.node = expr; + expression.push_back(e); + } + + //ok finally look for an operator + + int cofs = str_ofs; + _get_token(tk); + if (error_set) + return NULL; + + Variant::Operator op = Variant::OP_MAX; + + switch (tk.type) { + case TK_OP_IN: op = Variant::OP_IN; break; + case TK_OP_EQUAL: op = Variant::OP_EQUAL; break; + case TK_OP_NOT_EQUAL: op = Variant::OP_NOT_EQUAL; break; + case TK_OP_LESS: op = Variant::OP_LESS; break; + case TK_OP_LESS_EQUAL: op = Variant::OP_LESS_EQUAL; break; + case TK_OP_GREATER: op = Variant::OP_GREATER; break; + case TK_OP_GREATER_EQUAL: op = Variant::OP_GREATER_EQUAL; break; + case TK_OP_AND: op = Variant::OP_AND; break; + case TK_OP_OR: op = Variant::OP_OR; break; + case TK_OP_NOT: op = Variant::OP_NOT; break; + case TK_OP_ADD: op = Variant::OP_ADD; break; + case TK_OP_SUB: op = Variant::OP_SUBTRACT; break; + case TK_OP_MUL: op = Variant::OP_MULTIPLY; break; + case TK_OP_DIV: op = Variant::OP_DIVIDE; break; + case TK_OP_MOD: op = Variant::OP_MODULE; break; + case TK_OP_SHIFT_LEFT: op = Variant::OP_SHIFT_LEFT; break; + case TK_OP_SHIFT_RIGHT: op = Variant::OP_SHIFT_RIGHT; break; + case TK_OP_BIT_AND: op = Variant::OP_BIT_AND; break; + case TK_OP_BIT_OR: op = Variant::OP_BIT_OR; break; + case TK_OP_BIT_XOR: op = Variant::OP_BIT_XOR; break; + case TK_OP_BIT_INVERT: op = Variant::OP_BIT_NEGATE; break; + default: {}; + } + + if (op == Variant::OP_MAX) { //stop appending stuff + str_ofs = cofs; + break; + } + + //push operator and go on + { + ExpressionNode e; + e.is_op = true; + e.op = op; + expression.push_back(e); + } + } + + /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */ + + while (expression.size() > 1) { + + int next_op = -1; + int min_priority = 0xFFFFF; + bool is_unary = false; + + for (int i = 0; i < expression.size(); i++) { + + if (!expression[i].is_op) { + + continue; + } + + int priority; + + bool unary = false; + + switch (expression[i].op) { + + case Variant::OP_BIT_NEGATE: + priority = 0; + unary = true; + break; + case Variant::OP_NEGATE: + priority = 1; + unary = true; + break; + + case Variant::OP_MULTIPLY: priority = 2; break; + case Variant::OP_DIVIDE: priority = 2; break; + case Variant::OP_MODULE: priority = 2; break; + + case Variant::OP_ADD: priority = 3; break; + case Variant::OP_SUBTRACT: priority = 3; break; + + case Variant::OP_SHIFT_LEFT: priority = 4; break; + case Variant::OP_SHIFT_RIGHT: priority = 4; break; + + case Variant::OP_BIT_AND: priority = 5; break; + case Variant::OP_BIT_XOR: priority = 6; break; + case Variant::OP_BIT_OR: priority = 7; break; + + case Variant::OP_LESS: priority = 8; break; + case Variant::OP_LESS_EQUAL: priority = 8; break; + case Variant::OP_GREATER: priority = 8; break; + case Variant::OP_GREATER_EQUAL: priority = 8; break; + + case Variant::OP_EQUAL: priority = 8; break; + case Variant::OP_NOT_EQUAL: priority = 8; break; + + case Variant::OP_IN: priority = 10; break; + + case Variant::OP_NOT: + priority = 11; + unary = true; + break; + case Variant::OP_AND: priority = 12; break; + case Variant::OP_OR: priority = 13; break; + + default: { + _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op)); + return NULL; + } + } + + if (priority < min_priority) { + // < is used for left to right (default) + // <= is used for right to left + + next_op = i; + min_priority = priority; + is_unary = unary; + } + } + + if (next_op == -1) { + + _set_error("Yet another parser bug...."); + ERR_FAIL_COND_V(next_op == -1, NULL); + } + + // OK! create operator.. + if (is_unary) { + + int expr_pos = next_op; + while (expression[expr_pos].is_op) { + + expr_pos++; + if (expr_pos == expression.size()) { + //can happen.. + _set_error("Unexpected end of expression..."); + return NULL; + } + } + + //consecutively do unary opeators + for (int i = expr_pos - 1; i >= next_op; i--) { + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op = expression[i].op; + op->nodes[0] = expression[i + 1].node; + op->nodes[1] = NULL; + expression.write[i].is_op = false; + expression.write[i].node = op; + expression.remove(i + 1); + } + + } else { + + if (next_op < 1 || next_op >= (expression.size() - 1)) { + _set_error("Parser bug..."); + ERR_FAIL_V(NULL); + } + + OperatorNode *op = alloc_node<OperatorNode>(); + op->op = expression[next_op].op; + + if (expression[next_op - 1].is_op) { + + _set_error("Parser bug..."); + ERR_FAIL_V(NULL); + } + + if (expression[next_op + 1].is_op) { + // this is not invalid and can really appear + // but it becomes invalid anyway because no binary op + // can be followed by a unary op in a valid combination, + // due to how precedence works, unaries will always disappear first + + _set_error("Unexpected two consecutive operators."); + return NULL; + } + + op->nodes[0] = expression[next_op - 1].node; //expression goes as left + op->nodes[1] = expression[next_op + 1].node; //next expression goes as right + + //replace all 3 nodes by this operator and make it an expression + expression.write[next_op - 1].node = op; + expression.remove(next_op); + expression.remove(next_op); + } + } + + return expression[0].node; +} + +bool Expression::_compile_expression() { + + if (!expression_dirty) + return error_set; + + if (nodes) { + memdelete(nodes); + nodes = NULL; + root = NULL; + } + + error_str = String(); + error_set = false; + str_ofs = 0; + + root = _parse_expression(); + + if (error_set) { + root = NULL; + if (nodes) { + memdelete(nodes); + } + nodes = NULL; + return true; + } + + expression_dirty = false; + return false; +} + +bool Expression::_execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str) { + + switch (p_node->type) { + case Expression::ENode::TYPE_INPUT: { + + const Expression::InputNode *in = static_cast<const Expression::InputNode *>(p_node); + if (in->index < 0 || in->index >= p_inputs.size()) { + r_error_str = vformat(RTR("Invalid input %i (not passed) in expression"), in->index); + return true; + } + r_ret = p_inputs[in->index]; + } break; + case Expression::ENode::TYPE_CONSTANT: { + + const Expression::ConstantNode *c = static_cast<const Expression::ConstantNode *>(p_node); + r_ret = c->value; + + } break; + case Expression::ENode::TYPE_SELF: { + + if (!p_instance) { + r_error_str = RTR("self can't be used because instance is null (not passed)"); + return true; + } + r_ret = p_instance; + } break; + case Expression::ENode::TYPE_OPERATOR: { + + const Expression::OperatorNode *op = static_cast<const Expression::OperatorNode *>(p_node); + + Variant a; + bool ret = _execute(p_inputs, p_instance, op->nodes[0], a, r_error_str); + if (ret) + return true; + + Variant b; + + if (op->nodes[1]) { + bool ret = _execute(p_inputs, p_instance, op->nodes[1], b, r_error_str); + if (ret) + return true; + } + + bool valid = true; + Variant::evaluate(op->op, a, b, r_ret, valid); + if (!valid) { + r_error_str = vformat(RTR("Invalid operands to operator %s, %s and %s."), Variant::get_operator_name(op->op), Variant::get_type_name(a.get_type()), Variant::get_type_name(b.get_type())); + return true; + } + + } break; + case Expression::ENode::TYPE_INDEX: { + + const Expression::IndexNode *index = static_cast<const Expression::IndexNode *>(p_node); + + Variant base; + bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str); + if (ret) + return true; + + Variant idx; + + ret = _execute(p_inputs, p_instance, index->index, idx, r_error_str); + if (ret) + return true; + + bool valid; + r_ret = base.get(idx, &valid); + if (!valid) { + r_error_str = vformat(RTR("Invalid index of type %s for base type %s"), Variant::get_type_name(idx.get_type()), Variant::get_type_name(base.get_type())); + return true; + } + + } break; + case Expression::ENode::TYPE_NAMED_INDEX: { + + const Expression::NamedIndexNode *index = static_cast<const Expression::NamedIndexNode *>(p_node); + + Variant base; + bool ret = _execute(p_inputs, p_instance, index->base, base, r_error_str); + if (ret) + return true; + + bool valid; + r_ret = base.get_named(index->name, &valid); + if (!valid) { + r_error_str = vformat(RTR("Invalid named index '%s' for base type "), String(index->name), Variant::get_type_name(base.get_type())); + return true; + } + + } break; + case Expression::ENode::TYPE_ARRAY: { + const Expression::ArrayNode *array = static_cast<const Expression::ArrayNode *>(p_node); + + Array arr; + arr.resize(array->array.size()); + for (int i = 0; i < array->array.size(); i++) { + + Variant value; + bool ret = _execute(p_inputs, p_instance, array->array[i], value, r_error_str); + + if (ret) + return true; + arr[i] = value; + } + + r_ret = arr; + + } break; + case Expression::ENode::TYPE_DICTIONARY: { + const Expression::DictionaryNode *dictionary = static_cast<const Expression::DictionaryNode *>(p_node); + + Dictionary d; + for (int i = 0; i < dictionary->dict.size(); i += 2) { + + Variant key; + bool ret = _execute(p_inputs, p_instance, dictionary->dict[i + 0], key, r_error_str); + + if (ret) + return true; + + Variant value; + ret = _execute(p_inputs, p_instance, dictionary->dict[i + 1], value, r_error_str); + if (ret) + return true; + + d[key] = value; + } + + r_ret = d; + } break; + case Expression::ENode::TYPE_CONSTRUCTOR: { + + const Expression::ConstructorNode *constructor = static_cast<const Expression::ConstructorNode *>(p_node); + + Vector<Variant> arr; + Vector<const Variant *> argp; + arr.resize(constructor->arguments.size()); + argp.resize(constructor->arguments.size()); + + for (int i = 0; i < constructor->arguments.size(); i++) { + + Variant value; + bool ret = _execute(p_inputs, p_instance, constructor->arguments[i], value, r_error_str); + + if (ret) + return true; + arr.write[i] = value; + argp.write[i] = &arr[i]; + } + + Variant::CallError ce; + r_ret = Variant::construct(constructor->data_type, (const Variant **)argp.ptr(), argp.size(), ce); + + if (ce.error != Variant::CallError::CALL_OK) { + r_error_str = vformat(RTR("Invalid arguments to construct '%s'"), Variant::get_type_name(constructor->data_type)); + return true; + } + + } break; + case Expression::ENode::TYPE_BUILTIN_FUNC: { + + const Expression::BuiltinFuncNode *bifunc = static_cast<const Expression::BuiltinFuncNode *>(p_node); + + Vector<Variant> arr; + Vector<const Variant *> argp; + arr.resize(bifunc->arguments.size()); + argp.resize(bifunc->arguments.size()); + + for (int i = 0; i < bifunc->arguments.size(); i++) { + + Variant value; + bool ret = _execute(p_inputs, p_instance, bifunc->arguments[i], value, r_error_str); + if (ret) + return true; + arr.write[i] = value; + argp.write[i] = &arr[i]; + } + + Variant::CallError ce; + exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str); + + if (ce.error != Variant::CallError::CALL_OK) { + r_error_str = "Builtin Call Failed. " + r_error_str; + return true; + } + + } break; + case Expression::ENode::TYPE_CALL: { + + const Expression::CallNode *call = static_cast<const Expression::CallNode *>(p_node); + + Variant base; + bool ret = _execute(p_inputs, p_instance, call->base, base, r_error_str); + + if (ret) + return true; + + Vector<Variant> arr; + Vector<const Variant *> argp; + arr.resize(call->arguments.size()); + argp.resize(call->arguments.size()); + + for (int i = 0; i < call->arguments.size(); i++) { + + Variant value; + bool ret = _execute(p_inputs, p_instance, call->arguments[i], value, r_error_str); + + if (ret) + return true; + arr.write[i] = value; + argp.write[i] = &arr[i]; + } + + Variant::CallError ce; + r_ret = base.call(call->method, (const Variant **)argp.ptr(), argp.size(), ce); + + if (ce.error != Variant::CallError::CALL_OK) { + r_error_str = vformat(RTR("On call to '%s':"), String(call->method)); + return true; + } + + } break; + } + return false; +} + +Error Expression::parse(const String &p_expression, const Vector<String> &p_input_names) { + + if (nodes) { + memdelete(nodes); + nodes = NULL; + root = NULL; + } + + error_str = String(); + error_set = false; + str_ofs = 0; + input_names = p_input_names; + + expression = p_expression; + root = _parse_expression(); + + if (error_set) { + root = NULL; + if (nodes) { + memdelete(nodes); + } + nodes = NULL; + return ERR_INVALID_PARAMETER; + } + + return OK; +} + +Variant Expression::execute(Array p_inputs, Object *p_base, bool p_show_error) { + + execution_error = false; + Variant output; + String error_txt; + bool err = _execute(p_inputs, p_base, root, output, error_txt); + if (err) { + execution_error = true; + error_str = error_txt; + if (p_show_error) { + ERR_EXPLAIN(error_str); + ERR_FAIL_V(Variant()); + } + } + + return output; +} + +bool Expression::has_execute_failed() const { + return execution_error; +} + +String Expression::get_error_text() const { + return error_str; +} + +void Expression::_bind_methods() { + + ClassDB::bind_method(D_METHOD("parse", "expression", "input_names"), &Expression::parse, DEFVAL(Vector<String>())); + ClassDB::bind_method(D_METHOD("execute", "inputs", "base_instance", "show_error"), &Expression::execute, DEFVAL(Array()), DEFVAL(Variant()), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("has_execute_failed"), &Expression::has_execute_failed); + ClassDB::bind_method(D_METHOD("get_error_text"), &Expression::get_error_text); +} + +Expression::Expression() { + output_type = Variant::NIL; + error_set = true; + root = NULL; + nodes = NULL; + sequenced = false; + execution_error = false; +} + +Expression::~Expression() { + + if (nodes) { + memdelete(nodes); + } +} diff --git a/core/math/expression.h b/core/math/expression.h new file mode 100644 index 0000000000..7a7639cf0b --- /dev/null +++ b/core/math/expression.h @@ -0,0 +1,325 @@ +#ifndef EXPRESSION_H +#define EXPRESSION_H + +#include "core/reference.h" + +class Expression : public Reference { + GDCLASS(Expression, Reference) +public: + enum BuiltinFunc { + MATH_SIN, + MATH_COS, + MATH_TAN, + MATH_SINH, + MATH_COSH, + MATH_TANH, + MATH_ASIN, + MATH_ACOS, + MATH_ATAN, + MATH_ATAN2, + MATH_SQRT, + MATH_FMOD, + MATH_FPOSMOD, + MATH_FLOOR, + MATH_CEIL, + MATH_ROUND, + MATH_ABS, + MATH_SIGN, + MATH_POW, + MATH_LOG, + MATH_EXP, + MATH_ISNAN, + MATH_ISINF, + MATH_EASE, + MATH_DECIMALS, + MATH_STEPIFY, + MATH_LERP, + MATH_INVERSE_LERP, + MATH_RANGE_LERP, + MATH_DECTIME, + MATH_RANDOMIZE, + MATH_RAND, + MATH_RANDF, + MATH_RANDOM, + MATH_SEED, + MATH_RANDSEED, + MATH_DEG2RAD, + MATH_RAD2DEG, + MATH_LINEAR2DB, + MATH_DB2LINEAR, + MATH_POLAR2CARTESIAN, + MATH_CARTESIAN2POLAR, + MATH_WRAP, + MATH_WRAPF, + LOGIC_MAX, + LOGIC_MIN, + LOGIC_CLAMP, + LOGIC_NEAREST_PO2, + OBJ_WEAKREF, + FUNC_FUNCREF, + TYPE_CONVERT, + TYPE_OF, + TYPE_EXISTS, + TEXT_CHAR, + TEXT_STR, + TEXT_PRINT, + TEXT_PRINTERR, + TEXT_PRINTRAW, + VAR_TO_STR, + STR_TO_VAR, + VAR_TO_BYTES, + BYTES_TO_VAR, + COLORN, + FUNC_MAX + }; + + static int get_func_argument_count(BuiltinFunc p_func); + static String get_func_name(BuiltinFunc p_func); + static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Variant::CallError &r_error, String &r_error_str); + static BuiltinFunc find_function(const String &p_string); + +private: + static const char *func_name[FUNC_MAX]; + + struct Input { + + Variant::Type type; + String name; + + Input() { type = Variant::NIL; } + }; + + Vector<Input> inputs; + Variant::Type output_type; + + String expression; + + bool sequenced; + int str_ofs; + bool expression_dirty; + + bool _compile_expression(); + + enum TokenType { + TK_CURLY_BRACKET_OPEN, + TK_CURLY_BRACKET_CLOSE, + TK_BRACKET_OPEN, + TK_BRACKET_CLOSE, + TK_PARENTHESIS_OPEN, + TK_PARENTHESIS_CLOSE, + TK_IDENTIFIER, + TK_BUILTIN_FUNC, + TK_SELF, + TK_CONSTANT, + TK_BASIC_TYPE, + TK_COLON, + TK_COMMA, + TK_PERIOD, + TK_OP_IN, + TK_OP_EQUAL, + TK_OP_NOT_EQUAL, + TK_OP_LESS, + TK_OP_LESS_EQUAL, + TK_OP_GREATER, + TK_OP_GREATER_EQUAL, + TK_OP_AND, + TK_OP_OR, + TK_OP_NOT, + TK_OP_ADD, + TK_OP_SUB, + TK_OP_MUL, + TK_OP_DIV, + TK_OP_MOD, + TK_OP_SHIFT_LEFT, + TK_OP_SHIFT_RIGHT, + TK_OP_BIT_AND, + TK_OP_BIT_OR, + TK_OP_BIT_XOR, + TK_OP_BIT_INVERT, + TK_INPUT, + TK_EOF, + TK_ERROR, + TK_MAX + }; + + static const char *token_name[TK_MAX]; + struct Token { + + TokenType type; + Variant value; + }; + + void _set_error(const String &p_err) { + if (error_set) + return; + error_str = p_err; + error_set = true; + } + + Error _get_token(Token &r_token); + + String error_str; + bool error_set; + + struct ENode { + + enum Type { + TYPE_INPUT, + TYPE_CONSTANT, + TYPE_SELF, + TYPE_OPERATOR, + TYPE_INDEX, + TYPE_NAMED_INDEX, + TYPE_ARRAY, + TYPE_DICTIONARY, + TYPE_CONSTRUCTOR, + TYPE_BUILTIN_FUNC, + TYPE_CALL + }; + + ENode *next; + + Type type; + + ENode() { next = NULL; } + virtual ~ENode() { + if (next) { + memdelete(next); + } + } + }; + + struct ExpressionNode { + + bool is_op; + union { + Variant::Operator op; + ENode *node; + }; + }; + + ENode *_parse_expression(); + + struct InputNode : public ENode { + + int index; + InputNode() { + type = TYPE_INPUT; + } + }; + + struct ConstantNode : public ENode { + + Variant value; + ConstantNode() { + type = TYPE_CONSTANT; + } + }; + + struct OperatorNode : public ENode { + + Variant::Operator op; + + ENode *nodes[2]; + + OperatorNode() { + type = TYPE_OPERATOR; + } + }; + + struct SelfNode : public ENode { + + SelfNode() { + type = TYPE_SELF; + } + }; + + struct IndexNode : public ENode { + ENode *base; + ENode *index; + + IndexNode() { + type = TYPE_INDEX; + } + }; + + struct NamedIndexNode : public ENode { + ENode *base; + StringName name; + + NamedIndexNode() { + type = TYPE_NAMED_INDEX; + } + }; + + struct ConstructorNode : public ENode { + Variant::Type data_type; + Vector<ENode *> arguments; + + ConstructorNode() { + type = TYPE_CONSTRUCTOR; + } + }; + + struct CallNode : public ENode { + ENode *base; + StringName method; + Vector<ENode *> arguments; + + CallNode() { + type = TYPE_CALL; + } + }; + + struct ArrayNode : public ENode { + Vector<ENode *> array; + ArrayNode() { + type = TYPE_ARRAY; + } + }; + + struct DictionaryNode : public ENode { + Vector<ENode *> dict; + DictionaryNode() { + type = TYPE_DICTIONARY; + } + }; + + struct BuiltinFuncNode : public ENode { + BuiltinFunc func; + Vector<ENode *> arguments; + BuiltinFuncNode() { + type = TYPE_BUILTIN_FUNC; + } + }; + + template <class T> + T *alloc_node() { + T *node = memnew(T); + node->next = nodes; + nodes = node; + return node; + } + + ENode *root; + ENode *nodes; + + Vector<String> input_names; + + bool execution_error; + bool _execute(const Array &p_inputs, Object *p_instance, Expression::ENode *p_node, Variant &r_ret, String &r_error_str); + +protected: + static void _bind_methods(); + +public: + Error parse(const String &p_expression, const Vector<String> &p_input_names = Vector<String>()); + Variant execute(Array p_inputs, Object *p_base = NULL, bool p_show_error = true); + bool has_execute_failed() const; + String get_error_text() const; + + Expression(); + ~Expression(); +}; + +#endif // EXPRESSION_H diff --git a/core/object.cpp b/core/object.cpp index a0c64feb09..ba8b710a84 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -450,16 +450,41 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid *r_valid = true; return; #endif - } else { - //something inside the object... :| - bool success = _setv(p_name, p_value); - if (success) { + } + + //something inside the object... :| + bool success = _setv(p_name, p_value); + if (success) { + if (r_valid) + *r_valid = true; + return; + } + + { + bool valid; + setvar(p_name, p_value, &valid); + if (valid) { + if (r_valid) + *r_valid = true; + return; + } + } + +#ifdef TOOLS_ENABLED + if (script_instance) { + bool valid; + script_instance->property_set_fallback(p_name, p_value, &valid); + if (valid) { if (r_valid) *r_valid = true; return; } - setvar(p_name, p_value, r_valid); } +#endif + + if (r_valid) + *r_valid = false; + return; } Variant Object::get(const StringName &p_name, bool *r_valid) const { @@ -513,8 +538,33 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { *r_valid = true; return ret; } + //if nothing else, use getvar - return getvar(p_name, r_valid); + { + bool valid; + ret = getvar(p_name, &valid); + if (valid) { + if (r_valid) + *r_valid = true; + return ret; + } + } + +#ifdef TOOLS_ENABLED + if (script_instance) { + bool valid; + ret = script_instance->property_get_fallback(p_name, &valid); + if (valid) { + if (r_valid) + *r_valid = true; + return ret; + } + } +#endif + + if (r_valid) + *r_valid = false; + return Variant(); } } @@ -979,9 +1029,14 @@ void Object::set_script(const RefPtr &p_script) { script = p_script; Ref<Script> s(script); - if (!s.is_null() && s->can_instance()) { - OBJ_DEBUG_LOCK - script_instance = s->instance_create(this); + if (!s.is_null()) { + if (s->can_instance()) { + OBJ_DEBUG_LOCK + script_instance = s->instance_create(this); + } else if (Engine::get_singleton()->is_editor_hint()) { + OBJ_DEBUG_LOCK + script_instance = s->placeholder_instance_create(this); + } } _change_notify("script"); diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index 3eac4428da..59f07c03e7 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -270,7 +270,6 @@ String FileAccess::get_token() const { c = get_8(); } - token += '0'; return String::utf8(token.get_data()); } diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 0e7e63dbd8..859015f44b 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -54,6 +54,7 @@ #include "io/tcp_server.h" #include "io/translation_loader_po.h" #include "math/a_star.h" +#include "math/expression.h" #include "math/triangle_mesh.h" #include "os/input.h" #include "os/main_loop.h" @@ -216,6 +217,7 @@ void register_core_singletons() { ClassDB::register_virtual_class<Input>(); ClassDB::register_class<InputMap>(); ClassDB::register_class<_JSON>(); + ClassDB::register_class<Expression>(); Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton())); diff --git a/core/script_language.cpp b/core/script_language.cpp index 37ba3cfc62..e146fb773c 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -255,6 +255,17 @@ void ScriptInstance::call_multilevel_reversed(const StringName &p_method, const call(p_method, p_args, p_argcount, ce); // script may not support multilevel calls } +void ScriptInstance::property_set_fallback(const StringName &, const Variant &, bool *r_valid) { + if (r_valid) + *r_valid = false; +} + +Variant ScriptInstance::property_get_fallback(const StringName &, bool *r_valid) { + if (r_valid) + *r_valid = false; + return Variant(); +} + void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DECLARE) { VARIANT_ARGPTRS; @@ -364,6 +375,9 @@ ScriptDebugger::ScriptDebugger() { bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) { + if (build_failed) + return false; + if (values.has(p_name)) { Variant defval; if (script->get_property_default_value(p_name, defval)) { @@ -392,22 +406,31 @@ bool PlaceHolderScriptInstance::get(const StringName &p_name, Variant &r_ret) co return true; } - Variant defval; - if (script->get_property_default_value(p_name, defval)) { - r_ret = defval; - return true; + if (!build_failed) { + Variant defval; + if (script->get_property_default_value(p_name, defval)) { + r_ret = defval; + return true; + } } + return false; } void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const { - for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - PropertyInfo pinfo = E->get(); - if (!values.has(pinfo.name)) { - pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE; + if (build_failed) { + for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + p_properties->push_back(E->get()); + } + } else { + for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + PropertyInfo pinfo = E->get(); + if (!values.has(pinfo.name)) { + pinfo.usage |= PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE; + } + p_properties->push_back(E->get()); } - p_properties->push_back(E->get()); } } @@ -426,12 +449,18 @@ Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName &p_n void PlaceHolderScriptInstance::get_method_list(List<MethodInfo> *p_list) const { + if (build_failed) + return; + if (script.is_valid()) { script->get_script_method_list(p_list); } } bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { + if (build_failed) + return false; + if (script.is_valid()) { return script->has_method(p_method); } @@ -440,6 +469,8 @@ bool PlaceHolderScriptInstance::has_method(const StringName &p_method) const { void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values) { + build_failed = false; + Set<StringName> new_values; for (const List<PropertyInfo>::Element *E = p_properties.front(); E; E = E->next()) { @@ -483,6 +514,51 @@ void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties, c //change notify } +void PlaceHolderScriptInstance::property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid) { + + if (build_failed) { + Map<StringName, Variant>::Element *E = values.find(p_name); + + if (E) { + E->value() = p_value; + } else { + values.insert(p_name, p_value); + } + + bool found = false; + for (const List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (E->get().name == p_name) { + found = true; + break; + } + } + if (!found) { + properties.push_back(PropertyInfo(p_value.get_type(), p_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_SCRIPT_VARIABLE)); + } + } + + if (r_valid) + *r_valid = false; // Cannot change the value in either case +} + +Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_name, bool *r_valid) { + + if (build_failed) { + const Map<StringName, Variant>::Element *E = values.find(p_name); + + if (E) { + if (r_valid) + *r_valid = true; + return E->value(); + } + } + + if (r_valid) + *r_valid = false; + + return Variant(); +} + PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) : owner(p_owner), language(p_language), diff --git a/core/script_language.h b/core/script_language.h index 4e81b9b626..a5987e2a78 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -115,6 +115,7 @@ public: virtual StringName get_instance_base_type() const = 0; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this) = 0; + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) { return NULL; } virtual bool instance_has(const Object *p_this) const = 0; virtual bool has_source_code() const = 0; @@ -176,6 +177,9 @@ public: virtual bool is_placeholder() const { return false; } + virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); + virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; @@ -207,13 +211,20 @@ public: virtual void finish() = 0; /* EDITOR FUNCTIONS */ + struct Warning { + int line; + int code; + String string_code; + String message; + }; + virtual void get_reserved_words(List<String> *p_words) const = 0; virtual void get_comment_delimiters(List<String> *p_delimiters) const = 0; virtual void get_string_delimiters(List<String> *p_delimiters) const = 0; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0; virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {} virtual bool is_using_templates() { return false; } - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const = 0; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const = 0; virtual String validate_path(const String &p_path) const { return ""; } virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; @@ -319,6 +330,8 @@ class PlaceHolderScriptInstance : public ScriptInstance { ScriptLanguage *language; Ref<Script> script; + bool build_failed; + public: virtual bool set(const StringName &p_name, const Variant &p_value); virtual bool get(const StringName &p_name, Variant &r_ret) const; @@ -344,8 +357,14 @@ public: void update(const List<PropertyInfo> &p_properties, const Map<StringName, Variant> &p_values); //likely changed in editor + void set_build_failed(bool p_build_failed) { build_failed = p_build_failed; } + bool get_build_failed() const { return build_failed; } + virtual bool is_placeholder() const { return true; } + virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); + virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); + virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; } virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; } diff --git a/core/sort.h b/core/sort.h index a6780309d8..97983829e1 100644 --- a/core/sort.h +++ b/core/sort.h @@ -36,13 +36,25 @@ @author ,,, <red@lunatea> */ +#define ERR_BAD_COMPARE(cond) \ + if (unlikely(cond)) { \ + ERR_PRINT("bad comparison function; sorting will be broken"); \ + break; \ + } + template <class T> struct _DefaultComparator { - inline bool operator()(const T &a, const T &b) const { return (a < b); } + _FORCE_INLINE_ bool operator()(const T &a, const T &b) const { return (a < b); } }; -template <class T, class Comparator = _DefaultComparator<T> > +#ifdef DEBUG_ENABLED +#define SORT_ARRAY_VALIDATE_ENABLED true +#else +#define SORT_ARRAY_VALIDATE_ENABLED false +#endif + +template <class T, class Comparator = _DefaultComparator<T>, bool Validate = SORT_ARRAY_VALIDATE_ENABLED> class SortArray { enum { @@ -164,12 +176,23 @@ public: inline int partitioner(int p_first, int p_last, T p_pivot, T *p_array) const { + const int unmodified_first = p_first; + const int unmodified_last = p_last; + while (true) { - while (compare(p_array[p_first], p_pivot)) + while (compare(p_array[p_first], p_pivot)) { + if (Validate) { + ERR_BAD_COMPARE(p_first == unmodified_last - 1) + } p_first++; + } p_last--; - while (compare(p_pivot, p_array[p_last])) + while (compare(p_pivot, p_array[p_last])) { + if (Validate) { + ERR_BAD_COMPARE(p_last == unmodified_first) + } p_last--; + } if (!(p_first < p_last)) return p_first; @@ -238,6 +261,9 @@ public: int next = p_last - 1; while (compare(p_value, p_array[next])) { + if (Validate) { + ERR_BAD_COMPARE(next == 0) + } p_array[p_last] = p_array[next]; p_last = next; next--; diff --git a/core/ustring.cpp b/core/ustring.cpp index 84613610a9..35cd27f7f3 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -148,7 +148,7 @@ void String::copy_from(const char *p_cstr) { } } -void String::copy_from(const CharType *p_cstr, int p_clip_to) { +void String::copy_from(const CharType *p_cstr, const int p_clip_to) { if (!p_cstr) { @@ -158,12 +158,9 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) { int len = 0; const CharType *ptr = p_cstr; - while (*(ptr++) != 0) + while ((p_clip_to < 0 || len < p_clip_to) && *(ptr++) != 0) len++; - if (p_clip_to >= 0 && len > p_clip_to) - len = p_clip_to; - if (len == 0) { resize(0); @@ -177,7 +174,7 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) { // p_char != NULL // p_length > 0 // p_length <= p_char strlen -void String::copy_from_unchecked(const CharType *p_char, int p_length) { +void String::copy_from_unchecked(const CharType *p_char, const int p_length) { resize(p_length + 1); set(p_length, 0); @@ -2791,7 +2788,11 @@ String String::format(const Variant &values, String placeholder) const { val = val.substr(1, val.length() - 2); } - new_string = new_string.replace(placeholder.replace("_", i_as_str), val); + if (placeholder.find("_") > -1) { + new_string = new_string.replace(placeholder.replace("_", i_as_str), val); + } else { + new_string = new_string.replace_first(placeholder, val); + } } } } else if (values.get_type() == Variant::DICTIONARY) { @@ -3881,8 +3882,6 @@ String String::percent_decode() const { pe += c; } - pe += '0'; - return String::utf8(pe.ptr()); } diff --git a/core/ustring.h b/core/ustring.h index 3b4405833c..01397f6912 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -84,9 +84,9 @@ class String { CowData<CharType> _cowdata; void copy_from(const char *p_cstr); - void copy_from(const CharType *p_cstr, int p_clip_to = -1); + void copy_from(const CharType *p_cstr, const int p_clip_to = -1); void copy_from(const CharType &p_char); - void copy_from_unchecked(const CharType *p_char, int p_length); + void copy_from_unchecked(const CharType *p_char, const int p_length); bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const; public: diff --git a/core/variant.cpp b/core/variant.cpp index e4be5520bc..b0e97900a2 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1192,7 +1192,7 @@ Variant::operator int64_t() const { case BOOL: return _data._bool ? 1 : 0; case INT: return _data._int; case REAL: return _data._real; - case STRING: return operator String().to_int(); + case STRING: return operator String().to_int64(); default: { return 0; @@ -1460,7 +1460,7 @@ Variant::operator String() const { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); //const String *K=NULL; - String str; + String str("{"); List<Variant> keys; d.get_key_list(&keys); @@ -1479,8 +1479,9 @@ Variant::operator String() const { for (int i = 0; i < pairs.size(); i++) { if (i > 0) str += ", "; - str += "(" + pairs[i].key + ":" + pairs[i].value + ")"; + str += pairs[i].key + ":" + pairs[i].value; } + str += "}"; return str; } break; diff --git a/core/variant.h b/core/variant.h index 4b245d25e6..b48a0b3e73 100644 --- a/core/variant.h +++ b/core/variant.h @@ -398,9 +398,9 @@ public: void static_assign(const Variant &p_variant); static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list); - static void get_numeric_constants_for_type(Variant::Type p_type, List<StringName> *p_constants); - static bool has_numeric_constant(Variant::Type p_type, const StringName &p_value); - static int get_numeric_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = NULL); + static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants); + static bool has_constant(Variant::Type p_type, const StringName &p_value); + static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = NULL); typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud); typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 20a2929dc0..b312316f9a 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -30,6 +30,7 @@ #include "variant.h" +#include "core/color_names.inc" #include "core_string_names.h" #include "io/compression.h" #include "object.h" @@ -991,6 +992,7 @@ struct _VariantCall { #ifdef DEBUG_ENABLED List<StringName> value_ordered; #endif + Map<StringName, Variant> variant_value; }; static ConstantData *constant_data; @@ -1002,6 +1004,11 @@ struct _VariantCall { constant_data[p_type].value_ordered.push_back(p_constant_name); #endif } + + static void add_variant_constant(int p_type, StringName p_constant_name, const Variant &p_constant_value) { + + constant_data[p_type].variant_value[p_constant_name] = p_constant_value; + } }; _VariantCall::TypeFunc *_VariantCall::type_funcs = NULL; @@ -1152,7 +1159,7 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i return Variant(bool(*p_args[0])); } case INT: { - return (int(*p_args[0])); + return (int64_t(*p_args[0])); } case REAL: { return real_t(*p_args[0]); @@ -1354,7 +1361,7 @@ void Variant::get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_lis } } -void Variant::get_numeric_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) { +void Variant::get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants) { ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); @@ -1370,16 +1377,21 @@ void Variant::get_numeric_constants_for_type(Variant::Type p_type, List<StringNa p_constants->push_back(E->key()); #endif } + + for (Map<StringName, Variant>::Element *E = cd.variant_value.front(); E; E = E->next()) { + + p_constants->push_back(E->key()); + } } -bool Variant::has_numeric_constant(Variant::Type p_type, const StringName &p_value) { +bool Variant::has_constant(Variant::Type p_type, const StringName &p_value) { ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false); _VariantCall::ConstantData &cd = _VariantCall::constant_data[p_type]; - return cd.value.has(p_value); + return cd.value.has(p_value) || cd.variant_value.has(p_value); } -int Variant::get_numeric_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) { +Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid) { if (r_valid) *r_valid = false; @@ -1389,7 +1401,14 @@ int Variant::get_numeric_constant_value(Variant::Type p_type, const StringName & Map<StringName, int>::Element *E = cd.value.find(p_value); if (!E) { - return -1; + Map<StringName, Variant>::Element *E = cd.variant_value.find(p_value); + if (E) { + if (r_valid) + *r_valid = true; + return E->get(); + } else { + return -1; + } } if (r_valid) *r_valid = true; @@ -1858,9 +1877,62 @@ void register_variant_methods() { /* REGISTER CONSTANTS */ + _populate_named_colors(); + for (Map<String, Color>::Element *color = _named_colors.front(); color; color = color->next()) { + _VariantCall::add_variant_constant(Variant::COLOR, color->key(), color->value()); + } + _VariantCall::add_constant(Variant::VECTOR3, "AXIS_X", Vector3::AXIS_X); _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y); _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z); + + _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(Math_INF, Math_INF, Math_INF)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "LEFT", Vector3(-1, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "RIGHT", Vector3(1, 0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "UP", Vector3(0, 1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "DOWN", Vector3(0, -1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "FORWARD", Vector3(0, 0, -1)); + _VariantCall::add_variant_constant(Variant::VECTOR3, "BACK", Vector3(0, 0, 1)); + + _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(Math_INF, Math_INF)); + _VariantCall::add_variant_constant(Variant::VECTOR2, "LEFT", Vector2(-1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2, "RIGHT", Vector2(1, 0)); + _VariantCall::add_variant_constant(Variant::VECTOR2, "UP", Vector2(0, -1)); + _VariantCall::add_variant_constant(Variant::VECTOR2, "DOWN", Vector2(0, 1)); + + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D(1, 0, 0, 1, 0, 0)); + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); + + Transform identity_transform, transform_x, transform_y, transform_z; + identity_transform.set(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); + _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform); + transform_x.set(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); + _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", transform_x); + transform_x.set(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0); + _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", transform_y); + transform_x.set(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0); + _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", transform_z); + + _VariantCall::add_variant_constant(Variant::PLANE, "X", Plane(Vector3(1, 0, 0), 0)); + _VariantCall::add_variant_constant(Variant::PLANE, "Y", Plane(Vector3(0, 1, 0), 0)); + _VariantCall::add_variant_constant(Variant::PLANE, "Z", Plane(Vector3(0, 0, 1), 0)); + + _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1)); + + CharType black_circle[2] = { 0x25CF, 0 }; + _VariantCall::add_variant_constant(Variant::STRING, "BLACK_CIRCLE", String(black_circle)); + CharType white_circle[2] = { 0x25CB, 0 }; + _VariantCall::add_variant_constant(Variant::STRING, "WHITE_CIRCLE", String(white_circle)); + CharType black_diamond[2] = { 0x25C6, 0 }; + _VariantCall::add_variant_constant(Variant::STRING, "BLACK_DIAMOND", String(black_diamond)); + CharType white_diamond[2] = { 0x25C7, 0 }; + _VariantCall::add_variant_constant(Variant::STRING, "WHITE_DIAMOND", String(white_diamond)); + + _VariantCall::add_variant_constant(Variant::NODE_PATH, "CURRENT", String(".")); + _VariantCall::add_variant_constant(Variant::NODE_PATH, "PARENT", String("..")); } void unregister_variant_methods() { diff --git a/core/vector.h b/core/vector.h index 7e3da34be0..52e8758f9b 100644 --- a/core/vector.h +++ b/core/vector.h @@ -44,17 +44,16 @@ template <class T> class VectorWriteProxy { friend class Vector<T>; - Vector<T> &_parent; + CowData<T> *_parent; - _FORCE_INLINE_ VectorWriteProxy(Vector<T> &parent) : + _FORCE_INLINE_ VectorWriteProxy(CowData<T> *parent) : _parent(parent){}; - VectorWriteProxy(const VectorWriteProxy<T> &p_other); public: _FORCE_INLINE_ T &operator[](int p_index) { - CRASH_BAD_INDEX(p_index, _parent.size()); + CRASH_BAD_INDEX(p_index, _parent->size()); - return _parent.ptrw()[p_index]; + return _parent->ptrw()[p_index]; } }; @@ -62,39 +61,39 @@ template <class T> class Vector { friend class VectorWriteProxy<T>; - CowData<T> _cowdata; + CowData<T> *_cowdata; public: VectorWriteProxy<T> write; bool push_back(const T &p_elem); - void remove(int p_index) { _cowdata.remove(p_index); } + void remove(int p_index) { _cowdata->remove(p_index); } void erase(const T &p_val) { int idx = find(p_val); if (idx >= 0) remove(idx); }; void invert(); - _FORCE_INLINE_ T *ptrw() { return _cowdata.ptrw(); } - _FORCE_INLINE_ const T *ptr() const { return _cowdata.ptr(); } + _FORCE_INLINE_ T *ptrw() { return _cowdata->ptrw(); } + _FORCE_INLINE_ const T *ptr() const { return _cowdata->ptr(); } _FORCE_INLINE_ void clear() { resize(0); } - _FORCE_INLINE_ bool empty() const { return _cowdata.empty(); } + _FORCE_INLINE_ bool empty() const { return _cowdata->empty(); } - _FORCE_INLINE_ T get(int p_index) { return _cowdata.get(p_index); } - _FORCE_INLINE_ const T get(int p_index) const { return _cowdata.get(p_index); } - _FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata.set(p_index, p_elem); } - _FORCE_INLINE_ int size() const { return _cowdata.size(); } - Error resize(int p_size) { return _cowdata.resize(p_size); } - _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); } - Error insert(int p_pos, const T &p_val) { return _cowdata.insert(p_pos, p_val); } + _FORCE_INLINE_ T get(int p_index) { return _cowdata->get(p_index); } + _FORCE_INLINE_ const T get(int p_index) const { return _cowdata->get(p_index); } + _FORCE_INLINE_ void set(int p_index, const T &p_elem) { _cowdata->set(p_index, p_elem); } + _FORCE_INLINE_ int size() const { return _cowdata->size(); } + Error resize(int p_size) { return _cowdata->resize(p_size); } + _FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata->get(p_index); } + Error insert(int p_pos, const T &p_val) { return _cowdata->insert(p_pos, p_val); } void append_array(const Vector<T> &p_other); template <class C> void sort_custom() { - int len = _cowdata.size(); + int len = _cowdata->size(); if (len == 0) return; @@ -110,7 +109,7 @@ public: void ordered_insert(const T &p_val) { int i; - for (i = 0; i < _cowdata.size(); i++) { + for (i = 0; i < _cowdata->size(); i++) { if (p_val < operator[](i)) { break; @@ -136,13 +135,19 @@ public: } _FORCE_INLINE_ Vector() : - write(VectorWriteProxy<T>(*this)) {} + _cowdata(new CowData<T>()), + write(VectorWriteProxy<T>(_cowdata)) {} _FORCE_INLINE_ Vector(const Vector &p_from) : - write(VectorWriteProxy<T>(*this)) { _cowdata._ref(p_from._cowdata); } + _cowdata(new CowData<T>()), + write(VectorWriteProxy<T>(_cowdata)) { _cowdata->_ref(p_from._cowdata); } inline Vector &operator=(const Vector &p_from) { - _cowdata._ref(p_from._cowdata); + _cowdata->_ref(p_from._cowdata); return *this; } + + _FORCE_INLINE_ ~Vector() { + delete _cowdata; + } }; template <class T> diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml index 3ebe350700..2cfdfafea1 100644 --- a/doc/classes/@GDScript.xml +++ b/doc/classes/@GDScript.xml @@ -514,7 +514,8 @@ <argument index="0" name="var" type="Variant"> </argument> <description> - Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc. Note: Generates a fatal error if Variant can not provide a length. + Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc. + [b]Note:[/b] Generates a fatal error if Variant can not provide a length. [codeblock] a = [1, 2, 3, 4] len(a) # returns 4 @@ -552,7 +553,8 @@ <argument index="0" name="path" type="String"> </argument> <description> - Loads a resource from the filesystem located at [code]path[/code]. Note: resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path". + Loads a resource from the filesystem located at [code]path[/code]. + [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path". [codeblock] # load a scene called main located in the root of the project directory var main = load("res://main.tscn") @@ -565,7 +567,8 @@ <argument index="0" name="s" type="float"> </argument> <description> - Natural logarithm. The amount of time needed to reach a certain level of continuous growth. Note: This is not the same as the log function on your calculator which is a base 10 logarithm. + Natural logarithm. The amount of time needed to reach a certain level of continuous growth. + [b]Note:[/b] This is not the same as the log function on your calculator which is a base 10 logarithm. [codeblock] log(10) # returns 2.302585 [/codeblock] @@ -664,7 +667,8 @@ <argument index="0" name="path" type="String"> </argument> <description> - Returns a resource from the filesystem that is loaded during script parsing. Note: resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path". + Returns a resource from the filesystem that is loaded during script parsing. + [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path". [codeblock] # load a scene called main located in the root of the project directory var main = preload("res://main.tscn") diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index c6b868c058..74c6796b06 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -552,7 +552,8 @@ <argument index="1" name="path" type="NodePath"> </argument> <description> - Set the path of a track. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. Tracks that control properties or bones must append their name after the path, separated by ":". Example: "character/skeleton:ankle" or "character/mesh:transform/local" + Set the path of a track. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. Tracks that control properties or bones must append their name after the path, separated by ":". + [b]Example:[/b] "character/skeleton:ankle" or "character/mesh:transform/local". </description> </method> <method name="track_swap"> diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index f93590bb9d..6dc91a234a 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -283,5 +283,8 @@ <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode"> Process animation during the idle process. </constant> + <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode"> + Do not process animation. Use the 'advance' method to process the animation manually. + </constant> </constants> </class> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index a8e3a821b1..9b3679ae93 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -9,6 +9,14 @@ <demos> </demos> <methods> + <method name="advance"> + <return type="void"> + </return> + <argument index="0" name="delta" type="float"> + </argument> + <description> + </description> + </method> <method name="get_root_motion_transform" qualifiers="const"> <return type="Transform"> </return> @@ -33,5 +41,7 @@ </constant> <constant name="ANIMATION_PROCESS_IDLE" value="1" enum="AnimationProcessMode"> </constant> + <constant name="ANIMATION_PROCESS_MANUAL" value="2" enum="AnimationProcessMode"> + </constant> </constants> </class> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 7fcb827252..9c5ae8ebd0 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -300,7 +300,8 @@ <argument index="1" name="func" type="String"> </argument> <description> - Sort the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return true if the first argument is less than the second, and return false otherwise. Note: you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior. + Sort the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return true if the first argument is less than the second, and return false otherwise. + [b]Note:[/b] you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior. [codeblock] class MyCustomSorter: static func sort(a, b): diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml index 15bbb1625c..753a506058 100644 --- a/doc/classes/AudioStream.xml +++ b/doc/classes/AudioStream.xml @@ -16,6 +16,7 @@ <return type="float"> </return> <description> + Returns the length of the audio stream in seconds. </description> </method> </methods> diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index d6e75f8377..26d0b1a83d 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -17,7 +17,7 @@ <return type="float"> </return> <description> - Returns the position in the [AudioStream]. + Returns the position in the [AudioStream] in seconds. </description> </method> <method name="play"> diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml index 7070fdec4c..62c97feaf9 100644 --- a/doc/classes/BackBufferCopy.xml +++ b/doc/classes/BackBufferCopy.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="BackBufferCopy" inherits="Node2D" category="Core" version="3.1"> <brief_description> - Copies a region of the screen (or the whole screen) to a buffer so it can be accessed with the texscreen() shader instruction. + Copies a region of the screen (or the whole screen) to a buffer so it can be accessed with [code]SCREEN_TEXTURE[/code] in the [code]texture()[/code] function. </brief_description> <description> - Node for back-buffering the currently displayed screen. The region defined in the BackBufferCopy node is bufferized with the content of the screen it covers, or the entire screen according to the copy mode set. Accessing this buffer is done with the texscreen() shader instruction. + Node for back-buffering the currently displayed screen. The region defined in the BackBufferCopy node is bufferized with the content of the screen it covers, or the entire screen according to the copy mode set. Use [code]SCREEN_TEXTURE[/code] in the [code]texture()[/code] function to access the buffer. </description> <tutorials> </tutorials> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index 3d74bd7ab0..c675bbe994 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -5,7 +5,7 @@ </brief_description> <description> A color is represented as red, green and blue (r,g,b) components. Additionally, "a" represents the alpha component, often used for transparency. Values are in floating point and usually range from 0 to 1. Some methods (such as set_modulate(color)) may accept values > 1. - You can also create a color from standardised color names with [method @GDScript.ColorN]. + You can also create a color from standardised color names with Color.ColorN (e.g. Color.green) or [method @GDScript.ColorN]. </description> <tutorials> </tutorials> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 8c65f44259..d11b369e68 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -661,6 +661,7 @@ </member> <member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" enum="Control.CursorShape"> The default cursor shape for this control. Useful for Godot plugins and applications or games that use the system's mouse cursors. + [b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the system. </member> <member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" enum="Control.MouseFilter"> Controls whether the control will be able to receive mouse button input events through [method _gui_input] and how these events should be handled. Use one of the [code]MOUSE_FILTER_*[/code] constants. See the constants to learn what each does. diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml index bd1d6be4f5..48ca0ddc01 100644 --- a/doc/classes/ItemList.xml +++ b/doc/classes/ItemList.xml @@ -4,10 +4,8 @@ Control that provides a list of selectable items (and/or icons) in a single column, or optionally in multiple columns. </brief_description> <description> - This control provides a selectable list of items that may be in a single (or multiple columns) with option of text, icons, - or both text and icon. Tooltips are supported and may be different for every item in the list. Selectable items in the list - may be selected or deselected and multiple selection may be enabled. Selection with right mouse button may also be enabled - to allow use of popup context menus. Items may also be 'activated' with a double click (or Enter key). + This control provides a selectable list of items that may be in a single (or multiple columns) with option of text, icons, or both text and icon. Tooltips are supported and may be different for every item in the list. + Selectable items in the list may be selected or deselected and multiple selection may be enabled. Selection with right mouse button may also be enabled to allow use of popup context menus. Items may also be 'activated' with a double click (or Enter key). </description> <tutorials> </tutorials> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 7f8a43fda2..bfef3c8588 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -223,8 +223,8 @@ </argument> <description> Fetches a node. The [NodePath] can be either a relative path (from the current node) or an absolute path (in the scene tree) to a node. If the path does not exist, a [code]null instance[/code] is returned and attempts to access it will result in an "Attempt to call <method> on a null instance." error. - Note: fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]). - [i]Example:[/i] Assume your current node is Character and the following tree: + [b]Note:[/b] Fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]). + [b]Example:[/b] Assume your current node is Character and the following tree: [codeblock] /root /root/Character diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index ab49bc468c..a830468042 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -184,6 +184,8 @@ <argument index="0" name="property" type="NodePath"> </argument> <description> + Get indexed object property by String. + Property indices get accessed with colon seperation, for example: [code]position:x[/code] </description> </method> <method name="get_instance_id" qualifiers="const"> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index f5a19ede0c..c85bee9b84 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -384,20 +384,28 @@ Call a group only once even if the call is executed many times. </constant> <constant name="STRETCH_MODE_DISABLED" value="0" enum="StretchMode"> + No stretching. </constant> <constant name="STRETCH_MODE_2D" value="1" enum="StretchMode"> + Render stretching in higher resolution (interpolated). </constant> <constant name="STRETCH_MODE_VIEWPORT" value="2" enum="StretchMode"> + Keep the specified display resolution. No interpolation. Content may appear pixelated. </constant> <constant name="STRETCH_ASPECT_IGNORE" value="0" enum="StretchAspect"> + Fill the window with the content stretched to cover excessive space. Content may appear elongated. </constant> <constant name="STRETCH_ASPECT_KEEP" value="1" enum="StretchAspect"> + Retain the same aspect ratio by padding with black bars in either axes. No expansion of content. </constant> <constant name="STRETCH_ASPECT_KEEP_WIDTH" value="2" enum="StretchAspect"> + Expand vertically. Left/right black bars may appear if the window is too wide. </constant> <constant name="STRETCH_ASPECT_KEEP_HEIGHT" value="3" enum="StretchAspect"> + Expand horizontally. Top/bottom black bars may appear if the window is too tall. </constant> <constant name="STRETCH_ASPECT_EXPAND" value="4" enum="StretchAspect"> + Expand in both directions, retaining the same aspect ratio. No black bars. </constant> </constants> </class> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 0ba1066dfd..a42f508b59 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -653,7 +653,8 @@ <argument index="2" name="maxsplit" type="int" default="0"> </argument> <description> - Splits the string by a [code]divisor[/code] string and returns an array of the substrings, starting from right. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". + Splits the string by a [code]divisor[/code] string and returns an array of the substrings, starting from right. + [b]Example:[/b] "One,Two,Three" will return ["One","Two","Three"] if split by ",". If [code]maxsplit[/code] is specified, then it is number of splits to do, default is 0 which splits all the items. </description> </method> @@ -698,7 +699,8 @@ <argument index="2" name="maxsplit" type="int" default="0"> </argument> <description> - Splits the string by a divisor string and returns an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". + Splits the string by a divisor string and returns an array of the substrings. + [b]Example:[/b] "One,Two,Three" will return ["One","Two","Three"] if split by ",". If [code]maxsplit[/code] is given, at most maxsplit number of splits occur, and the remainder of the string is returned as the final element of the list (thus, the list will have at most maxsplit+1 elements) </description> </method> @@ -710,7 +712,8 @@ <argument index="1" name="allow_empty" type="bool" default="True"> </argument> <description> - Splits the string in floats by using a divisor string and returns an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",". + Splits the string in floats by using a divisor string and returns an array of the substrings. + [b]Example:[/b] "1,2.5,3" will return [1,2.5,3] if split by ",". </description> </method> <method name="strip_edges"> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 2990906f7c..73d60e49b7 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -68,7 +68,7 @@ <return type="Array"> </return> <description> - Returns an array of all cells containing a tile from the tileset (i.e. a tile index different from [code]-1[/code]). + Returns a [Vector2] array with the positions of all cells containing a tile from the tileset (i.e. a tile index different from [code]-1[/code]). </description> </method> <method name="get_used_cells_by_id" qualifiers="const"> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index 25426ee72c..533df57564 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -94,6 +94,8 @@ <argument index="0" name="position" type="Vector2"> </argument> <description> + If [member drop_mode_flags] includes [code]DROP_MODE_INBETWEEN[/code], returns -1 if [code]position[/code] is the upper part of a tree item at that position, 1 for the lower part, and additionally 0 for the middle part if [member drop_mode_flags] includes [code]DROP_MODE_ON_ITEM[/code]. + Otherwise, returns 0. If there are no tree item at [code]position[/code], returns -100. </description> </method> <method name="get_edited" qualifiers="const"> @@ -228,7 +230,7 @@ The amount of columns. </member> <member name="drop_mode_flags" type="int" setter="set_drop_mode_flags" getter="get_drop_mode_flags"> - The drop mode as an OR combination of flags. See [code]DROP_MODE_*[/code] constants. + The drop mode as an OR combination of flags. See [code]DROP_MODE_*[/code] constants. Once dropping is done, reverts to [code]DROP_MODE_DISABLED[/code]. Setting this during [method can_drop_data] is recommended. </member> <member name="hide_folding" type="bool" setter="set_hide_folding" getter="is_folding_hidden"> If [code]true[/code] the folding arrow is hidden. diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 2332c1a7aa..123226183a 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -170,7 +170,7 @@ <argument index="7" name="delay" type="float" default="0"> </argument> <description> - Animates [code]property[/code] of [code]object[/code] from [code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. + Animates [code]property[/code] of [code]object[/code] from [code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. Setting the initial value to [code]null[/code] uses the current value of the property. Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information </description> </method> diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index ac21de91e4..e1f47cb8c2 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -35,8 +35,23 @@ #include "os/os.h" #define kOutputBus 0 +#define kInputBus 1 #ifdef OSX_ENABLED +OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID, + UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, + void *inClientData) { + AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData; + + // If our selected device is the Default call set_device to update the + // kAudioOutputUnitProperty_CurrentDevice property + if (driver->capture_device_name == "Default") { + driver->capture_set_device("Default"); + } + + return noErr; +} + OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData) { @@ -79,6 +94,11 @@ Error AudioDriverCoreAudio::init() { result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); ERR_FAIL_COND_V(result != noErr, FAILED); + + prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); + ERR_FAIL_COND_V(result != noErr, FAILED); #endif AudioStreamBasicDescription strdesc; @@ -102,6 +122,26 @@ Error AudioDriverCoreAudio::init() { break; } + zeromem(&strdesc, sizeof(strdesc)); + size = sizeof(strdesc); + result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size); + ERR_FAIL_COND_V(result != noErr, FAILED); + + switch (strdesc.mChannelsPerFrame) { + case 1: // Mono + capture_channels = 1; + break; + + case 2: // Stereo + capture_channels = 2; + break; + + default: + // Unknown number of channels, default to stereo + capture_channels = 2; + break; + } + mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); zeromem(&strdesc, sizeof(strdesc)); @@ -117,6 +157,11 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); ERR_FAIL_COND_V(result != noErr, FAILED); + strdesc.mChannelsPerFrame = capture_channels; + + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc)); + ERR_FAIL_COND_V(result != noErr, FAILED); + int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) buffer_frames = closest_power_of_2(latency * mix_rate / 1000); @@ -126,8 +171,12 @@ Error AudioDriverCoreAudio::init() { ERR_FAIL_COND_V(result != noErr, FAILED); #endif - buffer_size = buffer_frames * channels; + unsigned int buffer_size = buffer_frames * channels; samples_in.resize(buffer_size); + input_buf.resize(buffer_size); + input_buffer.resize(buffer_size * 8); + input_position = 0; + input_size = 0; if (OS::get_singleton()->is_stdout_verbose()) { print_line("CoreAudio: detected " + itos(channels) + " channels"); @@ -141,6 +190,12 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); ERR_FAIL_COND_V(result != noErr, FAILED); + zeromem(&callback, sizeof(AURenderCallbackStruct)); + callback.inputProc = &AudioDriverCoreAudio::input_callback; + callback.inputProcRefCon = this; + result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback)); + ERR_FAIL_COND_V(result != noErr, FAILED); + result = AudioUnitInitialize(audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); @@ -192,6 +247,45 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, return 0; }; +OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData) { + + AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon; + if (!ad->active) { + return 0; + } + + ad->lock(); + + AudioBufferList bufferList; + bufferList.mNumberBuffers = 1; + bufferList.mBuffers[0].mData = ad->input_buf.ptrw(); + bufferList.mBuffers[0].mNumberChannels = ad->capture_channels; + bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t); + + OSStatus result = AudioUnitRender(ad->audio_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); + if (result == noErr) { + for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) { + int32_t sample = ad->input_buf[i] << 16; + ad->input_buffer_write(sample); + + if (ad->capture_channels == 1) { + // In case input device is single channel convert it to Stereo + ad->input_buffer_write(sample); + } + } + } else { + ERR_PRINT(("AudioUnitRender failed, code: " + itos(result)).utf8().get_data()); + } + + ad->unlock(); + + return result; +} + void AudioDriverCoreAudio::start() { if (!active) { OSStatus result = AudioOutputUnitStart(audio_unit); @@ -222,9 +316,94 @@ AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const { return get_speaker_mode_by_total_channels(channels); }; +void AudioDriverCoreAudio::lock() { + if (mutex) + mutex->lock(); +}; + +void AudioDriverCoreAudio::unlock() { + if (mutex) + mutex->unlock(); +}; + +bool AudioDriverCoreAudio::try_lock() { + if (mutex) + return mutex->try_lock() == OK; + return true; +} + +void AudioDriverCoreAudio::finish() { + OSStatus result; + + lock(); + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); + if (result != noErr) { + ERR_PRINT("AudioUnitSetProperty failed"); + } + + if (active) { + result = AudioOutputUnitStop(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioOutputUnitStop failed"); + } + + active = false; + } + + result = AudioUnitUninitialize(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioUnitUninitialize failed"); + } + #ifdef OSX_ENABLED + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; -Array AudioDriverCoreAudio::get_device_list() { + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); + if (result != noErr) { + ERR_PRINT("AudioObjectRemovePropertyListener failed"); + } +#endif + + result = AudioComponentInstanceDispose(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioComponentInstanceDispose failed"); + } + + unlock(); + + if (mutex) { + memdelete(mutex); + mutex = NULL; + } +}; + +Error AudioDriverCoreAudio::capture_start() { + + UInt32 flag = 1; + OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + return OK; +} + +Error AudioDriverCoreAudio::capture_stop() { + + UInt32 flag = 0; + OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + return OK; +} + +#ifdef OSX_ENABLED + +Array AudioDriverCoreAudio::_get_device_list(bool capture) { Array list; @@ -243,20 +422,20 @@ Array AudioDriverCoreAudio::get_device_list() { UInt32 deviceCount = size / sizeof(AudioDeviceID); for (UInt32 i = 0; i < deviceCount; i++) { - prop.mScope = kAudioDevicePropertyScopeOutput; + prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; prop.mSelector = kAudioDevicePropertyStreamConfiguration; AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size); AudioBufferList *bufferList = (AudioBufferList *)malloc(size); AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList); - UInt32 outputChannelCount = 0; + UInt32 channelCount = 0; for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) - outputChannelCount += bufferList->mBuffers[j].mNumberChannels; + channelCount += bufferList->mBuffers[j].mNumberChannels; free(bufferList); - if (outputChannelCount >= 1) { + if (channelCount >= 1) { CFStringRef cfname; size = sizeof(CFStringRef); @@ -281,21 +460,11 @@ Array AudioDriverCoreAudio::get_device_list() { return list; } -String AudioDriverCoreAudio::get_device() { - - return device_name; -} - -void AudioDriverCoreAudio::set_device(String device) { - - device_name = device; - if (!active) { - return; - } +void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { AudioDeviceID deviceId; bool found = false; - if (device_name != "Default") { + if (device != "Default") { AudioObjectPropertyAddress prop; prop.mSelector = kAudioHardwarePropertyDevices; @@ -309,20 +478,20 @@ void AudioDriverCoreAudio::set_device(String device) { UInt32 deviceCount = size / sizeof(AudioDeviceID); for (UInt32 i = 0; i < deviceCount && !found; i++) { - prop.mScope = kAudioDevicePropertyScopeOutput; + prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; prop.mSelector = kAudioDevicePropertyStreamConfiguration; AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size); AudioBufferList *bufferList = (AudioBufferList *)malloc(size); AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList); - UInt32 outputChannelCount = 0; + UInt32 channelCount = 0; for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++) - outputChannelCount += bufferList->mBuffers[j].mNumberChannels; + channelCount += bufferList->mBuffers[j].mNumberChannels; free(bufferList); - if (outputChannelCount >= 1) { + if (channelCount >= 1) { CFStringRef cfname; size = sizeof(CFStringRef); @@ -335,7 +504,7 @@ void AudioDriverCoreAudio::set_device(String device) { char *buffer = (char *)malloc(maxSize); if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) { String name = String(buffer) + " (" + itos(audioDevices[i]) + ")"; - if (name == device_name) { + if (name == device) { deviceId = audioDevices[i]; found = true; } @@ -351,7 +520,8 @@ void AudioDriverCoreAudio::set_device(String device) { if (!found) { // If we haven't found the desired device get the system default one UInt32 size = sizeof(AudioDeviceID); - AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + UInt32 elem = capture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice; + AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId); ERR_FAIL_COND(result != noErr); @@ -360,79 +530,52 @@ void AudioDriverCoreAudio::set_device(String device) { } if (found) { - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID)); + OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID)); ERR_FAIL_COND(result != noErr); + + // Reset audio input to keep synchronisation. + input_position = 0; + input_size = 0; } } -#endif - -void AudioDriverCoreAudio::lock() { - if (mutex) - mutex->lock(); -}; - -void AudioDriverCoreAudio::unlock() { - if (mutex) - mutex->unlock(); -}; +Array AudioDriverCoreAudio::get_device_list() { -bool AudioDriverCoreAudio::try_lock() { - if (mutex) - return mutex->try_lock() == OK; - return true; + return _get_device_list(); } -void AudioDriverCoreAudio::finish() { - OSStatus result; +String AudioDriverCoreAudio::get_device() { - lock(); + return device_name; +} - AURenderCallbackStruct callback; - zeromem(&callback, sizeof(AURenderCallbackStruct)); - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); - if (result != noErr) { - ERR_PRINT("AudioUnitSetProperty failed"); - } +void AudioDriverCoreAudio::set_device(String device) { + device_name = device; if (active) { - result = AudioOutputUnitStop(audio_unit); - if (result != noErr) { - ERR_PRINT("AudioOutputUnitStop failed"); - } - - active = false; + _set_device(device_name); } +} - result = AudioUnitUninitialize(audio_unit); - if (result != noErr) { - ERR_PRINT("AudioUnitUninitialize failed"); +void AudioDriverCoreAudio::capture_set_device(const String &p_name) { + + capture_device_name = p_name; + if (active) { + _set_device(capture_device_name, true); } +} -#ifdef OSX_ENABLED - AudioObjectPropertyAddress prop; - prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - prop.mScope = kAudioObjectPropertyScopeGlobal; - prop.mElement = kAudioObjectPropertyElementMaster; +Array AudioDriverCoreAudio::capture_get_device_list() { - result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); - if (result != noErr) { - ERR_PRINT("AudioObjectRemovePropertyListener failed"); - } -#endif + return _get_device_list(true); +} - result = AudioComponentInstanceDispose(audio_unit); - if (result != noErr) { - ERR_PRINT("AudioComponentInstanceDispose failed"); - } +String AudioDriverCoreAudio::capture_get_device() { - unlock(); + return capture_device_name; +} - if (mutex) { - memdelete(mutex); - mutex = NULL; - } -}; +#endif AudioDriverCoreAudio::AudioDriverCoreAudio() { active = false; @@ -440,14 +583,15 @@ AudioDriverCoreAudio::AudioDriverCoreAudio() { mix_rate = 0; channels = 2; + capture_channels = 2; - buffer_size = 0; buffer_frames = 0; samples_in.clear(); device_name = "Default"; -}; + capture_device_name = "Default"; +} AudioDriverCoreAudio::~AudioDriverCoreAudio(){}; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index 99c910498e..d3f7c8d596 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -48,15 +48,24 @@ class AudioDriverCoreAudio : public AudioDriver { Mutex *mutex; String device_name; + String capture_device_name; int mix_rate; unsigned int channels; + unsigned int capture_channels; unsigned int buffer_frames; - unsigned int buffer_size; Vector<int32_t> samples_in; + Vector<int16_t> input_buf; #ifdef OSX_ENABLED + Array _get_device_list(bool capture = false); + void _set_device(const String &device, bool capture = false); + + static OSStatus input_device_address_cb(AudioObjectID inObjectID, + UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, + void *inClientData); + static OSStatus output_device_address_cb(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inClientData); @@ -68,6 +77,12 @@ class AudioDriverCoreAudio : public AudioDriver { UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + static OSStatus input_callback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + public: const char *get_name() const { return "CoreAudio"; @@ -77,18 +92,27 @@ public: virtual void start(); virtual int get_mix_rate() const; virtual SpeakerMode get_speaker_mode() const; -#ifdef OSX_ENABLED - virtual Array get_device_list(); - virtual String get_device(); - virtual void set_device(String device); -#endif + virtual void lock(); virtual void unlock(); virtual void finish(); + virtual Error capture_start(); + virtual Error capture_stop(); + bool try_lock(); void stop(); +#ifdef OSX_ENABLED + virtual Array get_device_list(); + virtual String get_device(); + virtual void set_device(String device); + + virtual Array capture_get_device_list(); + virtual void capture_set_device(const String &p_name); + virtual String capture_get_device(); +#endif + AudioDriverCoreAudio(); ~AudioDriverCoreAudio(); }; diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index e045d4cd39..e39ec915fc 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -154,7 +154,8 @@ public: ERR_FAIL_COND_V(!texture, RID()); return texture_owner.make_rid(texture); } - void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) { + + void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type = VS::TEXTURE_TYPE_2D, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); t->width = p_width; @@ -164,7 +165,7 @@ public: t->image = Ref<Image>(memnew(Image)); t->image->create(p_width, p_height, false, p_format); } - void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) { + void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level) { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND(!t); t->width = p_image->get_width(); @@ -173,7 +174,7 @@ public: t->image->create(t->width, t->height, false, t->format, p_image->get_data()); } - void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) { + void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) { DummyTexture *t = texture_owner.get(p_texture); ERR_FAIL_COND(!t); @@ -186,7 +187,7 @@ public: t->image->blit_rect(p_image, Rect2(src_x, src_y, src_w, src_h), Vector2(dst_x, dst_y)); } - Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const { + Ref<Image> texture_get_data(RID p_texture, int p_level) const { DummyTexture *t = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!t, Ref<Image>()); return t->image; @@ -206,10 +207,13 @@ public: ERR_FAIL_COND_V(!t, Image::FORMAT_RGB8); return t->format; } + + VisualServer::TextureType texture_get_type(RID p_texture) const { return VS::TEXTURE_TYPE_2D; } uint32_t texture_get_texid(RID p_texture) const { return 0; } uint32_t texture_get_width(RID p_texture) const { return 0; } uint32_t texture_get_height(RID p_texture) const { return 0; } - void texture_set_size_override(RID p_texture, int p_width, int p_height) {} + uint32_t texture_get_depth(RID p_texture) const { return 0; } + void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) {} void texture_set_path(RID p_texture, const String &p_path) { DummyTexture *t = texture_owner.getornull(p_texture); diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 256d37186d..3d388c031a 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -349,7 +349,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } _bind_canvas_texture(RID(), RID()); @@ -393,7 +393,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); @@ -476,7 +476,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } glDisableVertexAttribArray(VS::ARRAY_COLOR); @@ -642,7 +642,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } static const int num_points = 32; @@ -673,7 +673,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); @@ -694,7 +694,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } _bind_canvas_texture(RID(), RID()); @@ -727,7 +727,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (state.canvas_shader.bind()) { _set_uniforms(); - state.canvas_shader.use_material((void *)p_material, 2); + state.canvas_shader.use_material((void *)p_material); } ERR_CONTINUE(primitive->points.size() < 1); @@ -926,7 +926,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons state.canvas_shader.set_custom_shader(0); state.canvas_shader.bind(); } - state.canvas_shader.use_material((void *)material_ptr, 2); + state.canvas_shader.use_material((void *)material_ptr); shader_cache = shader_ptr; diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 335ad28670..a1a0b9e2c6 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -317,7 +317,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c canvas->canvas_begin(); RID texture = storage->texture_create(); - storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER); + storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER); storage->texture_set_data(texture, p_image); Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 00a79db347..288a144b32 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -35,6 +35,8 @@ #include "rasterizer_canvas_gles2.h" #include "servers/visual/visual_server_raster.h" +#include "vmap.h" + #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif @@ -810,6 +812,14 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } } break; + case VS::INSTANCE_IMMEDIATE: { + RasterizerStorageGLES2::Immediate *im = storage->immediate_owner.getptr(instance->base); + ERR_CONTINUE(!im); + + _add_geometry(im, instance, NULL, -1, p_depth_pass, p_shadow_pass); + + } break; + default: { } break; @@ -827,7 +837,7 @@ static const GLenum gl_primitive[] = { GL_TRIANGLE_FAN }; -void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_use_radiance_map, bool p_reverse_cull, bool p_shadow_atlas, bool p_skeleton_tex, Size2i p_skeleton_tex_size) { +void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, Size2i p_skeleton_tex_size) { // material parameters @@ -864,25 +874,11 @@ void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw(); - int num_default_tex = p_use_radiance_map ? 1 : 0; - - if (p_material->shader->spatial.uses_screen_texture) { - num_default_tex = MIN(num_default_tex, 2); - } - - if (p_shadow_atlas) { - num_default_tex = MIN(num_default_tex, 3); - } - - if (p_skeleton_tex) { - num_default_tex = MIN(num_default_tex, 4); - - state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); - } + state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); for (int i = 0; i < tc; i++) { - glActiveTexture(GL_TEXTURE0 + num_default_tex + i); + glActiveTexture(GL_TEXTURE0 + i); RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i].second); @@ -911,7 +907,7 @@ void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m glBindTexture(t->target, t->tex_id); } - state.scene_shader.use_material((void *)p_material, num_default_tex); + state.scene_shader.use_material((void *)p_material); } void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) { @@ -943,6 +939,13 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled); } break; + case VS::INSTANCE_IMMEDIATE: { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); + state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true); + state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, true); + state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, true); + } break; + default: { } break; @@ -1276,10 +1279,122 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glBindBuffer(GL_ARRAY_BUFFER, 0); } break; + + case VS::INSTANCE_IMMEDIATE: { + const RasterizerStorageGLES2::Immediate *im = static_cast<const RasterizerStorageGLES2::Immediate *>(p_element->geometry); + + if (im->building) { + return; + } + + bool restore_tex = false; + + glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); + + for (const List<RasterizerStorageGLES2::Immediate::Chunk>::Element *E = im->chunks.front(); E; E = E->next()) { + const RasterizerStorageGLES2::Immediate::Chunk &c = E->get(); + + if (c.vertices.empty()) { + continue; + } + + int vertices = c.vertices.size(); + + uint32_t buf_ofs = 0; + + storage->info.render.vertices_count += vertices; + + if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { + RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(c.texture); + + t = t->get_ptr(); + + if (t->redraw_if_visible) { + VisualServerRaster::redraw_request(); + } + +#ifdef TOOLS_ENABLED + if (t->detect_3d) { + t->detect_3d(t->detect_3d_ud); + } +#endif + if (t->render_target) { + t->render_target->used_in_frame = true; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(t->target, t->tex_id); + restore_tex = true; + } else if (restore_tex) { + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, state.current_main_tex); + restore_tex = false; + } + + if (!c.normals.empty()) { + glEnableVertexAttribArray(VS::ARRAY_NORMAL); + glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr()); + glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs); + buf_ofs += sizeof(Vector3) * vertices; + } else { + glDisableVertexAttribArray(VS::ARRAY_NORMAL); + } + + if (!c.tangents.empty()) { + glEnableVertexAttribArray(VS::ARRAY_TANGENT); + glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr()); + glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), ((uint8_t *)NULL) + buf_ofs); + buf_ofs += sizeof(Plane) * vertices; + } else { + glDisableVertexAttribArray(VS::ARRAY_TANGENT); + } + + if (!c.colors.empty()) { + glEnableVertexAttribArray(VS::ARRAY_COLOR); + glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr()); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)NULL) + buf_ofs); + buf_ofs += sizeof(Color) * vertices; + } else { + glDisableVertexAttribArray(VS::ARRAY_COLOR); + } + + if (!c.uvs.empty()) { + glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr()); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs); + buf_ofs += sizeof(Vector2) * vertices; + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + } + + if (!c.uv2s.empty()) { + glEnableVertexAttribArray(VS::ARRAY_TEX_UV2); + glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uv2s.ptr()); + glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs); + buf_ofs += sizeof(Vector2) * vertices; + } else { + glDisableVertexAttribArray(VS::ARRAY_TEX_UV2); + } + + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr()); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs); + + glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size()); + } + + if (restore_tex) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, state.current_main_tex); + restore_tex = false; + } + + } break; } } -void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_light_cull_result, int p_light_cull_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows) { +void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); @@ -1289,6 +1404,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, bool use_radiance_map = false; + VMap<RID, Vector<RenderList::Element *> > lit_objects; + for (int i = 0; i < p_element_count; i++) { RenderList::Element *e = p_elements[i]; @@ -1297,7 +1414,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); if (p_base_env) { - glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env); use_radiance_map = true; } @@ -1315,7 +1432,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _setup_geometry(e, skeleton); - _setup_material(material, use_radiance_map, p_reverse_cull, false, skeleton ? (skeleton->tex_id != 0) : 0, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + _setup_material(material, p_reverse_cull, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); if (use_radiance_map) { state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); @@ -1404,66 +1521,88 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _render_geometry(e); - // render lights - if (material->shader->spatial.unshaded) continue; if (p_shadow) continue; - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true); + for (int light = 0; light < e->instance->light_instances.size(); light++) { - state.scene_shader.bind(); + RID light_instance = e->instance->light_instances[light]; - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + lit_objects[light_instance].push_back(e); + } + } - { - bool has_shadow_atlas = shadow_atlas != NULL; - _setup_material(material, false, p_reverse_cull, has_shadow_atlas, skeleton ? (skeleton->tex_id != 0) : 0, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + if (p_shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); + return; + } - if (has_shadow_atlas) { - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - } + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + for (int lo = 0; lo < lit_objects.size(); lo++) { - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); - } + RID key = lit_objects.getk(lo); - for (int j = 0; j < e->instance->light_instances.size(); j++) { - RID light_rid = e->instance->light_instances[j]; - LightInstance *light = light_instance_owner.get(light_rid); + LightInstance *light = light_instance_owner.getornull(key); + RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; - switch (light->light_ptr->type) { - case VS::LIGHT_DIRECTIONAL: { - continue; - } break; + const Vector<RenderList::Element *> &list = lit_objects.getv(lo); + + for (int i = 0; i < list.size(); i++) { + + RenderList::Element *e = list[i]; + RasterizerStorageGLES2::Material *material = e->material; + RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + + { + _setup_geometry(e, skeleton); + + _setup_material(material, p_reverse_cull, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + if (shadow_atlas != NULL) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + } + + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + + state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + + state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); + state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? + state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + } + + switch (light_ptr->type) { case VS::LIGHT_OMNI: { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)1); Vector3 position = p_view_transform.inverse().xform(light->transform.origin); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - float range = light->light_ptr->param[VS::LIGHT_PARAM_RANGE]; + float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - if (light->light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { + if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { uint32_t key = shadow_atlas->shadow_owners[light->self]; @@ -1516,10 +1655,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - float range = light->light_ptr->param[VS::LIGHT_PARAM_RANGE]; - float spot_attenuation = light->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - float angle = light->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; + attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; + float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; + float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; angle = Math::cos(Math::deg2rad(angle)); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation); @@ -1576,9 +1715,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } break; - default: { - print_line("wat."); - } break; + default: break; } float energy = light->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; @@ -1590,62 +1727,57 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _render_geometry(e); } + } - for (int j = 0; j < p_light_cull_count; j++) { - RID light_rid = p_light_cull_result[j]; - - LightInstance *light = light_instance_owner.getornull(light_rid); + for (int dl = 0; dl < p_directional_light_count; dl++) { + RID light_rid = p_directional_lights[dl]; + LightInstance *light = light_instance_owner.getornull(light_rid); + RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; - RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; + switch (light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); + } break; - switch (light_ptr->type) { - case VS::LIGHT_DIRECTIONAL: { - - switch (light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); - } break; - - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); - } break; - default: - break; - } + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); + } break; + default: + break; + } - { - _setup_material(material, false, p_reverse_cull, false, skeleton ? (skeleton->tex_id != 0) : 0, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + for (int i = 0; i < p_element_count; i++) { - if (directional_shadow.depth) { - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - } + RenderList::Element *e = p_elements[i]; + RasterizerStorageGLES2::Material *material = e->material; + RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + { + _setup_material(material, p_reverse_cull, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + if (directional_shadow.depth) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); // TODO move into base pass + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + } - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); - } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0); - Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); - } break; + state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); - default: { - continue; - } break; + state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); + state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? + state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); } + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0); + Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY]; float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; @@ -1753,10 +1885,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _render_geometry(e); } - - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false); } + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); @@ -1899,7 +2031,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } break; default: { - print_line("uhm"); + // FIXME: implement other background modes } break; } } @@ -1911,9 +2043,21 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } } + Vector<RID> directional_lights; + + for (int i = 0; i < p_light_cull_count; i++) { + RID light_rid = p_light_cull_result[i]; + + LightInstance *light = light_instance_owner.getornull(light_rid); + + if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) { + directional_lights.push_back(light_rid); + } + } + // render opaque things first render_list.sort_by_key(false); - _render_render_list(render_list.elements, render_list.element_count, p_light_cull_result, p_light_cull_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false, false); + _render_render_list(render_list.elements, render_list.element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false); // alpha pass @@ -1921,7 +2065,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); render_list.sort_by_key(true); - _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_light_cull_result, p_light_cull_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false, false); + _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false); glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); @@ -2136,7 +2280,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true); - _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false, false); + _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false); state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false); @@ -2230,6 +2374,15 @@ void RasterizerSceneGLES2::initialize() { glBindBuffer(GL_ARRAY_BUFFER, 0); } + { + uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); + + glGenBuffers(1, &state.immediate_buffer); + glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); + glBufferData(GL_ARRAY_BUFFER, immediate_buffer_size * 1024, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + // cubemaps for shadows { int max_shadow_cubemap_sampler_size = 512; diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 0ce7e9ae97..e153080e15 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -74,6 +74,8 @@ public: GLuint sky_verts; + GLuint immediate_buffer; + // ResolveShaderGLES3 resolve_shader; // ScreenSpaceReflectionShaderGLES3 ssr_shader; // EffectBlurShaderGLES3 effect_blur_shader; @@ -545,11 +547,23 @@ public: void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass); void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); - void _render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_light_cull_result, int p_light_cull_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows); + void _render_render_list(RenderList::Element **p_elements, int p_element_count, + const RID *p_directional_lights, int p_directional_light_count, + const Transform &p_view_transform, + const CameraMatrix &p_projection, + RID p_shadow_atlas, + Environment *p_env, + GLuint p_base_env, + float p_shadow_bias, + float p_shadow_normal_bias, + bool p_reverse_cull, + bool p_alpha_pass, + bool p_shadow, + bool p_directional_add); void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy); - void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_use_radiance_map, bool p_reverse_cull, bool p_shadow_atlas = false, bool p_skeleton_tex = false, Size2i p_skeleton_tex_size = Size2i(0, 0)); + void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, Size2i p_skeleton_tex_size = Size2i(0, 0)); void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); void _render_geometry(RenderList::Element *p_element); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 468659ed80..1bd3c0a935 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -346,7 +346,7 @@ RID RasterizerStorageGLES2::texture_create() { return texture_owner.make_rid(texture); } -void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) { +void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) { GLenum format; GLenum internal_format; GLenum type; @@ -365,7 +365,24 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ texture->format = p_format; texture->flags = p_flags; texture->stored_cube_sides = 0; - texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + texture->type = p_type; + + switch (p_type) { + case VS::TEXTURE_TYPE_2D: { + texture->target = GL_TEXTURE_2D; + texture->images.resize(1); + } break; + case VS::TEXTURE_TYPE_CUBEMAP: { + texture->target = GL_TEXTURE_CUBE_MAP; + texture->images.resize(6); + } break; + case VS::TEXTURE_TYPE_2D_ARRAY: { + texture->images.resize(p_depth_3d); + } break; + case VS::TEXTURE_TYPE_3D: { + texture->images.resize(p_depth_3d); + } break; + } _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed); @@ -391,7 +408,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ texture->active = true; } -void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side) { +void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) { Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); @@ -406,7 +423,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p bool compressed = false; if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { - texture->images[p_cube_side] = p_image; + texture->images.write[p_layer] = p_image; } Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed); @@ -425,7 +442,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p } }; - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D; + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; texture->data_size = img->get_data().size(); PoolVector<uint8_t>::Read read = img->get_data().read(); @@ -527,9 +544,9 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p // printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem); - texture->stored_cube_sides |= (1 << p_cube_side); + texture->stored_cube_sides |= (1 << p_layer); - if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) { + if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) { //generate mipmaps if they were requested and the image does not contain them glGenerateMipmap(texture->target); } @@ -537,12 +554,12 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p texture->mipmaps = mipmaps; } -void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) { +void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) { // TODO ERR_PRINT("Not implemented (ask Karroffel to do it :p)"); } -Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const { +Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) const { Texture *texture = texture_owner.getornull(p_texture); @@ -550,8 +567,8 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSi ERR_FAIL_COND_V(!texture->active, Ref<Image>()); ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>()); - if (!texture->images[p_cube_side].is_null()) { - return texture->images[p_cube_side]; + if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) { + return texture->images[p_layer]; } #ifdef GLES_OVER_GL @@ -577,9 +594,13 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSi ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, i - 1); } - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]); + if (texture->compressed) { + glPixelStorei(GL_PACK_ALIGNMENT, 4); + glGetCompressedTexImage(texture->target, i, &wb[ofs]); + } else { + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]); + } } wb = PoolVector<uint8_t>::Write(); @@ -605,8 +626,6 @@ void RasterizerStorageGLES2::texture_set_flags(RID p_texture, uint32_t p_flags) glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); - uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; - texture->flags = p_flags | cube; // can't remove a cube from being a cube if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { @@ -663,6 +682,14 @@ Image::Format RasterizerStorageGLES2::texture_get_format(RID p_texture) const { return texture->format; } +VisualServer::TextureType RasterizerStorageGLES2::texture_get_type(RID p_texture) const { + Texture *texture = texture_owner.getornull(p_texture); + + ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D); + + return texture->type; +} + uint32_t RasterizerStorageGLES2::texture_get_texid(RID p_texture) const { Texture *texture = texture_owner.getornull(p_texture); @@ -687,7 +714,15 @@ uint32_t RasterizerStorageGLES2::texture_get_height(RID p_texture) const { return texture->height; } -void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height) { +uint32_t RasterizerStorageGLES2::texture_get_depth(RID p_texture) const { + Texture *texture = texture_owner.getornull(p_texture); + + ERR_FAIL_COND_V(!texture, 0); + + return texture->depth; +} + +void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) { Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); @@ -726,8 +761,9 @@ void RasterizerStorageGLES2::texture_debug_usage(List<VS::TextureInfo> *r_info) VS::TextureInfo tinfo; tinfo.path = t->path; tinfo.format = t->format; - tinfo.size.x = t->alloc_width; - tinfo.size.y = t->alloc_height; + tinfo.width = t->alloc_width; + tinfo.height = t->alloc_height; + tinfo.depth = 0; tinfo.bytes = t->total_data_size; r_info->push_back(tinfo); } @@ -2643,45 +2679,132 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() { /* IMMEDIATE API */ RID RasterizerStorageGLES2::immediate_create() { - return RID(); + Immediate *im = memnew(Immediate); + return immediate_owner.make_rid(im); } -void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture) { +void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + + Immediate::Chunk ic; + ic.texture = p_texture; + ic.primitive = p_primitive; + im->chunks.push_back(ic); + im->mask = 0; + im->building = true; } void RasterizerStorageGLES2::immediate_vertex(RID p_immediate, const Vector3 &p_vertex) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + Immediate::Chunk *c = &im->chunks.back()->get(); + + if (c->vertices.empty() && im->chunks.size() == 1) { + im->aabb.position = p_vertex; + im->aabb.size = Vector3(); + } else { + im->aabb.expand_to(p_vertex); + } + + if (im->mask & VS::ARRAY_FORMAT_NORMAL) + c->normals.push_back(chunk_normal); + if (im->mask & VS::ARRAY_FORMAT_TANGENT) + c->tangents.push_back(chunk_tangent); + if (im->mask & VS::ARRAY_FORMAT_COLOR) + c->colors.push_back(chunk_color); + if (im->mask & VS::ARRAY_FORMAT_TEX_UV) + c->uvs.push_back(chunk_uv); + if (im->mask & VS::ARRAY_FORMAT_TEX_UV2) + c->uv2s.push_back(chunk_uv2); + im->mask |= VS::ARRAY_FORMAT_VERTEX; + c->vertices.push_back(p_vertex); } void RasterizerStorageGLES2::immediate_normal(RID p_immediate, const Vector3 &p_normal) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask |= VS::ARRAY_FORMAT_NORMAL; + chunk_normal = p_normal; } void RasterizerStorageGLES2::immediate_tangent(RID p_immediate, const Plane &p_tangent) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask |= VS::ARRAY_FORMAT_TANGENT; + chunk_tangent = p_tangent; } void RasterizerStorageGLES2::immediate_color(RID p_immediate, const Color &p_color) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask |= VS::ARRAY_FORMAT_COLOR; + chunk_color = p_color; } void RasterizerStorageGLES2::immediate_uv(RID p_immediate, const Vector2 &tex_uv) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask |= VS::ARRAY_FORMAT_TEX_UV; + chunk_uv = tex_uv; } void RasterizerStorageGLES2::immediate_uv2(RID p_immediate, const Vector2 &tex_uv) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->mask |= VS::ARRAY_FORMAT_TEX_UV2; + chunk_uv2 = tex_uv; } void RasterizerStorageGLES2::immediate_end(RID p_immediate) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(!im->building); + + im->building = false; + im->instance_change_notify(); } void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + ERR_FAIL_COND(im->building); + + im->chunks.clear(); + im->instance_change_notify(); } AABB RasterizerStorageGLES2::immediate_get_aabb(RID p_immediate) const { - return AABB(); + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im, AABB()); + return im->aabb; } void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_material) { + Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND(!im); + + im->material = p_material; + im->instance_material_change_notify(); } RID RasterizerStorageGLES2::immediate_get_material(RID p_immediate) const { - return RID(); + const Immediate *im = immediate_owner.get(p_immediate); + ERR_FAIL_COND_V(!im, RID()); + return im->material; } /* SKELETON API */ @@ -3693,15 +3816,15 @@ VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const { if (mesh_owner.owns(p_rid)) { return VS::INSTANCE_MESH; - } - if (light_owner.owns(p_rid)) { + } else if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; - } - if (multimesh_owner.owns(p_rid)) { + } else if (multimesh_owner.owns(p_rid)) { return VS::INSTANCE_MULTIMESH; + } else if (immediate_owner.owns(p_rid)) { + return VS::INSTANCE_IMMEDIATE; + } else { + return VS::INSTANCE_NONE; } - - return VS::INSTANCE_NONE; } bool RasterizerStorageGLES2::free(RID p_rid) { @@ -3859,6 +3982,14 @@ bool RasterizerStorageGLES2::free(RID p_rid) { memdelete(multimesh); return true; + } else if (immediate_owner.owns(p_rid)) { + Immediate *im = immediate_owner.get(p_rid); + im->instance_remove_deps(); + + immediate_owner.free(p_rid); + memdelete(im); + + return true; } else if (light_owner.owns(p_rid)) { Light *light = light_owner.get(p_rid); @@ -3929,7 +4060,7 @@ void RasterizerStorageGLES2::initialize() { frame.clear_request = false; // config.keep_original_textures = false; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); shaders.copy.init(); diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index fe5d4af952..c1fbf73254 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -231,9 +231,10 @@ public: String path; uint32_t flags; - int width, height; + int width, height, depth; int alloc_width, alloc_height; Image::Format format; + VS::TextureType type; GLenum target; GLenum gl_format_cache; @@ -257,7 +258,7 @@ public: RenderTarget *render_target; - Ref<Image> images[6]; + Vector<Ref<Image> > images; bool redraw_if_visible; @@ -327,17 +328,19 @@ public: Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed); virtual RID texture_create(); - virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); - virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const; + virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); + virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); + virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0); + virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const; virtual void texture_set_flags(RID p_texture, uint32_t p_flags); virtual uint32_t texture_get_flags(RID p_texture) const; virtual Image::Format texture_get_format(RID p_texture) const; + virtual VS::TextureType texture_get_type(RID p_texture) const; virtual uint32_t texture_get_texid(RID p_texture) const; virtual uint32_t texture_get_width(RID p_texture) const; virtual uint32_t texture_get_height(RID p_texture) const; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height); + virtual uint32_t texture_get_depth(RID p_texture) const; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth); virtual void texture_set_path(RID p_texture, const String &p_path); virtual String texture_get_path(RID p_texture) const; @@ -794,8 +797,40 @@ public: /* IMMEDIATE API */ + struct Immediate : public Geometry { + + struct Chunk { + RID texture; + VS::PrimitiveType primitive; + Vector<Vector3> vertices; + Vector<Vector3> normals; + Vector<Plane> tangents; + Vector<Color> colors; + Vector<Vector2> uvs; + Vector<Vector2> uv2s; + }; + + List<Chunk> chunks; + bool building; + int mask; + AABB aabb; + + Immediate() { + type = GEOMETRY_IMMEDIATE; + building = false; + } + }; + + Vector3 chunk_normal; + Plane chunk_tangent; + Color chunk_color; + Vector2 chunk_uv; + Vector2 chunk_uv2; + + mutable RID_Owner<Immediate> immediate_owner; + virtual RID immediate_create(); - virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture = RID()); + virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture = RID()); virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex); virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal); virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 6c7f767733..5ac2af6e5c 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -704,6 +704,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } code += ";\n"; } else if (cf_node->flow_op == SL::FLOW_OP_DISCARD) { + if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) { + *p_actions.usage_flag_pointers["DISCARD"] = true; + used_flag_pointers.insert("DISCARD"); + } code += "discard;"; } else if (cf_node->flow_op == SL::FLOW_OP_CONTINUE) { code += "continue;"; diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 146575973f..e9b58cb272 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -527,8 +527,13 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { for (int i = 0; i < texunit_pair_count; i++) { GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name); - if (loc >= 0) - glUniform1i(loc, texunit_pairs[i].index); + if (loc >= 0) { + if (texunit_pairs[i].index < 0) { + glUniform1i(loc, max_image_units + texunit_pairs[i].index); + } else { + glUniform1i(loc, texunit_pairs[i].index); + } + } } if (cc) { @@ -643,6 +648,8 @@ void ShaderGLES2::setup( } } } + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units); } void ShaderGLES2::finish() { @@ -717,7 +724,7 @@ void ShaderGLES2::free_custom_shader(uint32_t p_code_id) { custom_code_map.erase(p_code_id); } -void ShaderGLES2::use_material(void *p_material, int p_num_predef_textures) { +void ShaderGLES2::use_material(void *p_material) { RasterizerStorageGLES2::Material *material = (RasterizerStorageGLES2::Material *)p_material; if (!material) { @@ -906,20 +913,58 @@ void ShaderGLES2::use_material(void *p_material, int p_num_predef_textures) { case ShaderLanguage::TYPE_MAT2: { Transform2D val = V->get(); - // TODO + if (value.second.size() < 4) { + value.second.resize(4); + } + + value.second.write[0].real = val.elements[0][0]; + value.second.write[1].real = val.elements[0][1]; + value.second.write[2].real = val.elements[1][0]; + value.second.write[3].real = val.elements[1][1]; } break; case ShaderLanguage::TYPE_MAT3: { Basis val = V->get(); - // TODO + if (value.second.size() < 9) { + value.second.resize(9); + } + + value.second.write[0].real = val.elements[0][0]; + value.second.write[1].real = val.elements[0][1]; + value.second.write[2].real = val.elements[0][2]; + value.second.write[3].real = val.elements[1][0]; + value.second.write[4].real = val.elements[1][1]; + value.second.write[5].real = val.elements[1][2]; + value.second.write[6].real = val.elements[2][0]; + value.second.write[7].real = val.elements[2][1]; + value.second.write[8].real = val.elements[2][2]; } break; case ShaderLanguage::TYPE_MAT4: { Transform val = V->get(); - // TODO + if (value.second.size() < 16) { + value.second.resize(16); + } + + value.second.write[0].real = val.basis.elements[0][0]; + value.second.write[1].real = val.basis.elements[0][1]; + value.second.write[2].real = val.basis.elements[0][2]; + value.second.write[3].real = 0; + value.second.write[4].real = val.basis.elements[1][0]; + value.second.write[5].real = val.basis.elements[1][1]; + value.second.write[6].real = val.basis.elements[1][2]; + value.second.write[7].real = 0; + value.second.write[8].real = val.basis.elements[2][0]; + value.second.write[9].real = val.basis.elements[2][1]; + value.second.write[10].real = val.basis.elements[2][2]; + value.second.write[11].real = 0; + value.second.write[12].real = val.origin[0]; + value.second.write[13].real = val.origin[1]; + value.second.write[14].real = val.origin[2]; + value.second.write[15].real = 1; } break; case ShaderLanguage::TYPE_SAMPLER2D: { @@ -1034,7 +1079,7 @@ void ShaderGLES2::use_material(void *p_material, int p_num_predef_textures) { Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value; value.first = ShaderLanguage::TYPE_INT; value.second.resize(1); - value.second.write[0].sint = p_num_predef_textures + i; + value.second.write[0].sint = i; // GLint location = get_uniform_location(textures[i].first); diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index 0c53c4ba72..cb515c199c 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -300,7 +300,7 @@ public: case ShaderLanguage::TYPE_MAT3: { GLfloat mat[9]; - for (int i = 0; i < 0; i++) { + for (int i = 0; i < 9; i++) { mat[i] = values[i].real; } @@ -311,7 +311,7 @@ public: case ShaderLanguage::TYPE_MAT4: { GLfloat mat[16]; - for (int i = 0; i < 0; i++) { + for (int i = 0; i < 16; i++) { mat[i] = values[i].real; } @@ -465,7 +465,7 @@ public: // this void* is actually a RasterizerStorageGLES2::Material, but C++ doesn't // like forward declared nested classes. - void use_material(void *p_material, int p_num_predef_textures); + void use_material(void *p_material); uint32_t get_version() const { return new_conditional_version.version; } diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index e08e9d1117..9251e21080 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -48,7 +48,7 @@ attribute highp vec4 bone_transform_row_2; // attrib:11 attribute vec4 bone_ids; // attrib:6 attribute highp vec4 bone_weights; // attrib:7 -uniform highp sampler2D bone_transforms; // texunit:4 +uniform highp sampler2D bone_transforms; // texunit:-1 uniform ivec2 skeleton_texture_size; #endif @@ -181,7 +181,7 @@ void main() { #else // look up transform from the "pose texture" { - + for (int i = 0; i < 4; i++) { ivec2 tex_ofs = ivec2(int(bone_ids[i]) * 3, 0); @@ -252,7 +252,7 @@ VERTEX_SHADER_CODE float z_ofs = light_bias; z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; - + vertex_interp.z -= z_ofs; #endif @@ -294,17 +294,17 @@ uniform highp float time; uniform vec2 screen_pixel_size; #endif -uniform highp sampler2D depth_buffer; //texunit:1 +uniform highp sampler2D depth_buffer; //texunit:-5 #if defined(SCREEN_TEXTURE_USED) -uniform highp sampler2D screen_texture; //texunit:2 +uniform highp sampler2D screen_texture; //texunit:-6 #endif #ifdef USE_RADIANCE_MAP #define RADIANCE_MAX_LOD 6.0 -uniform samplerCube radiance_map; // texunit:0 +uniform samplerCube radiance_map; // texunit:-2 uniform mat4 radiance_inverse_xform; @@ -345,7 +345,7 @@ uniform float light_spot_angle; // shadows -uniform highp sampler2D light_shadow_atlas; //texunit:3 +uniform highp sampler2D light_shadow_atlas; //texunit:-4 uniform float light_has_shadow; uniform mat4 light_shadow_matrix; @@ -353,7 +353,7 @@ uniform vec4 light_clamp; // directional shadow -uniform highp sampler2D light_directional_shadow; // texunit:3 +uniform highp sampler2D light_directional_shadow; // texunit:-4 uniform vec4 light_split_offsets; uniform mat4 light_shadow_matrix1; @@ -439,11 +439,10 @@ void light_compute(vec3 N, { // calculate specular reflection - vec3 R = normalize(-reflect(L,N)); - float cRdotV = max(dot(R, V), 0.0); - float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0); - specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity; - + vec3 R = normalize(-reflect(L,N)); + float cRdotV = max(dot(R, V), 0.0); + float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0); + specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity; } } @@ -460,7 +459,7 @@ float sample_shadow(highp sampler2D shadow, vec4 clamp_rect) { // vec4 depth_value = texture2D(shadow, pos); - + // return depth_value.z; return texture2DProj(shadow, vec4(pos, depth, 1.0)).r; // return (depth_value.x + depth_value.y + depth_value.z + depth_value.w) / 4.0; @@ -469,22 +468,22 @@ float sample_shadow(highp sampler2D shadow, #endif -void main() +void main() { highp vec3 vertex = vertex_interp; - vec3 albedo = vec3(0.8, 0.8, 0.8); + vec3 albedo = vec3(1.0); vec3 transmission = vec3(0.0); float metallic = 0.0; float specular = 0.5; - vec3 emission = vec3(0.0, 0.0, 0.0); + vec3 emission = vec3(0.0); float roughness = 1.0; float rim = 0.0; float rim_tint = 0.0; float clearcoat = 0.0; float clearcoat_gloss = 0.0; - float anisotropy = 1.0; - vec2 anisotropy_flow = vec2(1.0,0.0); + float anisotropy = 0.0; + vec2 anisotropy_flow = vec2(1.0, 0.0); float alpha = 1.0; float side = 1.0; @@ -536,7 +535,7 @@ FRAGMENT_SHADER_CODE normal = normalize(normal); vec3 N = normal; - + vec3 specular_light = vec3(0.0, 0.0, 0.0); vec3 diffuse_light = vec3(0.0, 0.0, 0.0); @@ -551,7 +550,7 @@ FRAGMENT_SHADER_CODE discard; } #endif - + // // Lighting // @@ -621,11 +620,11 @@ FRAGMENT_SHADER_CODE vec3 light_vec = -light_direction; vec3 attenuation = vec3(1.0, 1.0, 1.0); - + float depth_z = -vertex.z; - + if (light_has_shadow > 0.5) { - + #ifdef LIGHT_USE_PSSM4 if (depth_z < light_split_offsets.w) { #elif defined(LIGHT_USE_PSSM2) @@ -633,36 +632,36 @@ FRAGMENT_SHADER_CODE #else if (depth_z < light_split_offsets.x) { #endif - + vec3 pssm_coord; float pssm_fade = 0.0; - + #ifdef LIGHT_USE_PSSM_BLEND float pssm_blend; vec3 pssm_coord2; bool use_blend = true; #endif - + #ifdef LIGHT_USE_PSSM4 if (depth_z < light_split_offsets.y) { if (depth_z < light_split_offsets.x) { highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); pssm_coord = splane.xyz / splane.w; - + #ifdef LIGHT_USE_PSSM_BLEND splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); pssm_coord2 = splane.xyz / splane.w; - + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif } else { highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); pssm_coord = splane.xyz / splane.w; - + #ifdef LIGHT_USE_PSSM_BLEND splane = (light_shadow_matrix3 * vec4(vertex, 1.0)); pssm_coord2 = splane.xyz / splane.w; - + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #endif } @@ -689,15 +688,15 @@ FRAGMENT_SHADER_CODE #endif } } - + #endif // LIGHT_USE_PSSM4 - + #ifdef LIGHT_USE_PSSM2 if (depth_z < light_split_offsets.x) { - + highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); pssm_coord = splane.xyz / splane.w; - + #ifdef LIGHT_USE_PSSM_BLEND splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); pssm_coord2 = splane.xyz / splane.w; @@ -711,29 +710,29 @@ FRAGMENT_SHADER_CODE use_blend = false; #endif } - + #endif // LIGHT_USE_PSSM2 - + #if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) { highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); pssm_coord = splane.xyz / splane.w; } #endif - + float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord.xy, pssm_coord.z, light_clamp); - + #ifdef LIGHT_USE_PSSM_BLEND if (use_blend) { shadow = mix(shadow, sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend); } #endif - + attenuation *= shadow; - - + + } - + } light_compute(normal, @@ -758,19 +757,19 @@ FRAGMENT_SHADER_CODE } else if (light_type == LIGHT_TYPE_SPOT) { vec3 light_att = vec3(1.0); - + if (light_has_shadow > 0.5) { highp vec4 splane = (light_shadow_matrix * vec4(vertex, 1.0)); splane.xyz /= splane.w; - + float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, light_clamp); - + if (shadow > splane.z) { } else { light_att = vec3(0.0); } - - + + } vec3 light_rel_vec = light_position - vertex; @@ -788,7 +787,7 @@ FRAGMENT_SHADER_CODE spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); light_att *= vec3(spot_attenuation); - + light_compute(normal, normalize(light_rel_vec), eye_position, @@ -808,7 +807,6 @@ FRAGMENT_SHADER_CODE anisotropy, diffuse_light, specular_light); - } gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); @@ -837,9 +835,9 @@ FRAGMENT_SHADER_CODE } ambient_light *= ambient_energy; - + specular_light += env_reflection_light; - + ambient_light *= albedo; #if defined(ENABLE_AO) @@ -848,12 +846,12 @@ FRAGMENT_SHADER_CODE specular_light *= ao_light_affect; diffuse_light *= ao_light_affect; #endif - + diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; - + // environment BRDF approximation - + // TODO shadeless { const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 0053b6311f..cb17695c5f 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -290,7 +290,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c canvas->canvas_begin(); RID texture = storage->texture_create(); - storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER); + storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER); storage->texture_set_data(texture, p_image); Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index d01ba2ddcc..eebdbe9493 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1190,6 +1190,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m int tc = p_material->textures.size(); RID *textures = p_material->textures.ptrw(); ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw(); + const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr(); state.current_main_tex = 0; @@ -1198,39 +1199,17 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m glActiveTexture(GL_TEXTURE0 + i); GLenum target; - GLuint tex; + GLuint tex = 0; - RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull(textures[i]); + RasterizerStorageGLES3::Texture *t = storage->texture_owner.getptr(textures[i]); - if (!t) { - //check hints - target = GL_TEXTURE_2D; - - switch (texture_hints[i]) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { - tex = storage->resources.black_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - tex = storage->resources.aniso_tex; - } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { - tex = storage->resources.normal_tex; - - } break; - default: { - tex = storage->resources.white_tex; - } break; - } - - } else { + if (t) { if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies VisualServerRaster::redraw_request(); } t = t->get_ptr(); //resolve for proxies - #ifdef TOOLS_ENABLED if (t->detect_3d) { t->detect_3d(t->detect_3d_ud); @@ -1247,6 +1226,59 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m target = t->target; tex = t->tex_id; + } else { + + switch (texture_types[i]) { + case ShaderLanguage::TYPE_ISAMPLER2D: + case ShaderLanguage::TYPE_USAMPLER2D: + case ShaderLanguage::TYPE_SAMPLER2D: { + target = GL_TEXTURE_2D; + + switch (texture_hints[i]) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: { + tex = storage->resources.black_tex; + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { + tex = storage->resources.aniso_tex; + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: { + tex = storage->resources.normal_tex; + + } break; + default: { + tex = storage->resources.white_tex; + } break; + } + + } break; + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + // TODO + } break; + + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: + case ShaderLanguage::TYPE_SAMPLER3D: { + + target = GL_TEXTURE_3D; + + switch (texture_hints[i]) { + + // TODO + default: { + tex = storage->resources.white_tex_3d; + } break; + } + + } break; + + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER2DARRAY: { + // TODO + } break; + } } glBindTexture(target, tex); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index c1c1b2a009..a5c81d6c4d 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -595,7 +595,7 @@ RID RasterizerStorageGLES3::texture_create() { return texture_owner.make_rid(texture); } -void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) { +void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) { GLenum format; GLenum internal_format; @@ -612,15 +612,37 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_ ERR_FAIL_COND(!texture); texture->width = p_width; texture->height = p_height; + texture->depth = p_depth_3d; texture->format = p_format; texture->flags = p_flags; texture->stored_cube_sides = 0; - texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + + texture->type = p_type; + + switch (p_type) { + case VS::TEXTURE_TYPE_2D: { + texture->target = GL_TEXTURE_2D; + texture->images.resize(1); + } break; + case VS::TEXTURE_TYPE_CUBEMAP: { + texture->target = GL_TEXTURE_CUBE_MAP; + texture->images.resize(6); + } break; + case VS::TEXTURE_TYPE_2D_ARRAY: { + texture->target = GL_TEXTURE_2D_ARRAY; + texture->images.resize(p_depth_3d); + } break; + case VS::TEXTURE_TYPE_3D: { + texture->target = GL_TEXTURE_3D; + texture->images.resize(p_depth_3d); + } break; + } _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed, srgb); texture->alloc_width = texture->width; texture->alloc_height = texture->height; + texture->alloc_depth = texture->depth; texture->gl_format_cache = format; texture->gl_type_cache = type; @@ -633,7 +655,34 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_ glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); - if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + if (p_type == VS::TEXTURE_TYPE_3D || p_type == VS::TEXTURE_TYPE_2D_ARRAY) { + + int width = p_width; + int height = p_height; + int depth = p_depth_3d; + + int mipmaps = 0; + + while (width != 1 && height != 1) { + glTexImage3D(texture->target, 0, internal_format, width, height, depth, 0, format, type, NULL); + + width = MAX(1, width / 2); + height = MAX(1, height / 2); + + if (p_type == VS::TEXTURE_TYPE_3D) { + depth = MAX(1, depth / 2); + } + + mipmaps++; + + if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS)) + break; + } + + glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); + + } else if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { //prealloc if video glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL); } @@ -641,7 +690,7 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_ texture->active = true; } -void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side) { +void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) { Texture *texture = texture_owner.get(p_texture); @@ -658,7 +707,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p bool srgb; if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { - texture->images[p_cube_side] = p_image; + texture->images.write[p_layer] = p_image; } Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed, srgb); @@ -677,7 +726,23 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p } }; - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D; + GLenum blit_target; + + switch (texture->type) { + case VS::TEXTURE_TYPE_2D: { + blit_target = GL_TEXTURE_2D; + } break; + case VS::TEXTURE_TYPE_CUBEMAP: { + ERR_FAIL_INDEX(p_layer, 6); + blit_target = _cube_side_enum[p_layer]; + } break; + case VS::TEXTURE_TYPE_2D_ARRAY: { + blit_target = GL_TEXTURE_2D_ARRAY; + } break; + case VS::TEXTURE_TYPE_3D: { + blit_target = GL_TEXTURE_3D; + } break; + } texture->data_size = img->get_data().size(); PoolVector<uint8_t>::Read read = img->get_data().read(); @@ -785,20 +850,36 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p //print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h)); - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { + + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - int bw = w; - int bh = h; + int bw = w; + int bh = h; - glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); + glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + } else { + glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + } + } } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { - glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]); + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + + int bw = w; + int bh = h; + + glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]); } else { - glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]); } } tsize += size; @@ -813,14 +894,17 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p //printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem); - texture->stored_cube_sides |= (1 << p_cube_side); + texture->stored_cube_sides |= (1 << p_layer); - if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) { + if ((texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) && (texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) { //generate mipmaps if they were requested and the image does not contain them glGenerateMipmap(texture->target); } else if (mipmaps > 1) { glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1); + } else { + glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 0); } texture->mipmaps = mipmaps; @@ -831,7 +915,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p // Uploads pixel data to a sub-region of a texture, for the specified mipmap. // The texture pixels must have been allocated before, because most features seen in texture_set_data() make no sense in a partial update. // TODO If we want this to be usable without pre-filling pixels with a full image, we have to call glTexImage2D() with null data. -void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) { +void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) { Texture *texture = texture_owner.get(p_texture); @@ -859,7 +943,23 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, format, internal_format, type, compressed, srgb); - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D; + GLenum blit_target; + + switch (texture->type) { + case VS::TEXTURE_TYPE_2D: { + blit_target = GL_TEXTURE_2D; + } break; + case VS::TEXTURE_TYPE_CUBEMAP: { + ERR_FAIL_INDEX(p_layer, 6); + blit_target = _cube_side_enum[p_layer]; + } break; + case VS::TEXTURE_TYPE_2D_ARRAY: { + blit_target = GL_TEXTURE_2D_ARRAY; + } break; + case VS::TEXTURE_TYPE_3D: { + blit_target = GL_TEXTURE_3D; + } break; + } PoolVector<uint8_t>::Read read = img->get_data().read(); @@ -869,18 +969,38 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I int src_data_size = img->get_data().size(); int src_ofs = 0; - if (texture->compressed) { - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]); + if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // `format` has to match the internal_format used when the texture was created + glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]); + } } else { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - // `format` has to match the internal_format used when the texture was created - glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]); + if (texture->compressed) { + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glCompressedTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, src_data_size, &read[src_ofs]); + } else { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // `format` has to match the internal_format used when the texture was created + glTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, type, &read[src_ofs]); + } + } + + if (texture->flags & VS::TEXTURE_FLAG_FILTER) { + + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering + + } else { + + glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering } } -Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const { +Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) const { Texture *texture = texture_owner.get(p_texture); @@ -888,8 +1008,8 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSi ERR_FAIL_COND_V(!texture->active, Ref<Image>()); ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>()); - if (!texture->images[p_cube_side].is_null()) { - return texture->images[p_cube_side]; + if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && !texture->images[p_layer].is_null()) { + return texture->images[p_layer]; } #ifdef GLES_OVER_GL @@ -977,10 +1097,10 @@ void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags) bool had_mipmaps = texture->flags & VS::TEXTURE_FLAG_MIPMAPS; + texture->flags = p_flags; + glActiveTexture(GL_TEXTURE0); glBindTexture(texture->target, texture->tex_id); - uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; - texture->flags = p_flags | cube; // can't remove a cube from being a cube if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { @@ -1058,6 +1178,14 @@ Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const { return texture->format; } + +VisualServer::TextureType RasterizerStorageGLES3::texture_get_type(RID p_texture) const { + Texture *texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D); + + return texture->type; +} uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const { Texture *texture = texture_owner.get(p_texture); @@ -1083,7 +1211,16 @@ uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const { return texture->height; } -void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height) { +uint32_t RasterizerStorageGLES3::texture_get_depth(RID p_texture) const { + + Texture *texture = texture_owner.get(p_texture); + + ERR_FAIL_COND_V(!texture, 0); + + return texture->depth; +} + +void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) { Texture *texture = texture_owner.get(p_texture); @@ -1123,8 +1260,9 @@ void RasterizerStorageGLES3::texture_debug_usage(List<VS::TextureInfo> *r_info) VS::TextureInfo tinfo; tinfo.path = t->path; tinfo.format = t->format; - tinfo.size.x = t->alloc_width; - tinfo.size.y = t->alloc_height; + tinfo.width = t->alloc_width; + tinfo.height = t->alloc_height; + tinfo.depth = 0; tinfo.bytes = t->total_data_size; r_info->push_back(tinfo); } @@ -1169,7 +1307,7 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_ Texture *texture = texture_owner.get(p_source); ERR_FAIL_COND_V(!texture, RID()); - ERR_FAIL_COND_V(!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP), RID()); + ERR_FAIL_COND_V(texture->type != VS::TEXTURE_TYPE_CUBEMAP, RID()); bool use_float = config.hdr_supported; @@ -1285,7 +1423,8 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_ Texture *ctex = memnew(Texture); - ctex->flags = VS::TEXTURE_FLAG_CUBEMAP | VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER; + ctex->type = VS::TEXTURE_TYPE_CUBEMAP; + ctex->flags = VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER; ctex->width = p_resolution; ctex->height = p_resolution; ctex->alloc_width = p_resolution; @@ -1765,6 +1904,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->ubo_offsets = gen_code.uniform_offsets; p_shader->texture_count = gen_code.texture_uniforms.size(); p_shader->texture_hints = gen_code.texture_hints; + p_shader->texture_types = gen_code.texture_types; p_shader->uses_vertex_time = gen_code.uses_vertex_time; p_shader->uses_fragment_time = gen_code.uses_fragment_time; @@ -1875,6 +2015,13 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture"; } break; + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "Texture3D"; + } break; case ShaderLanguage::TYPE_SAMPLERCUBE: { pi.type = Variant::OBJECT; @@ -2649,6 +2796,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { //set up the texture array, for easy access when it needs to be drawn if (material->shader && material->shader->texture_count) { + material->texture_is_3d.resize(material->shader->texture_count); material->textures.resize(material->shader->texture_count); for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { @@ -2658,6 +2806,16 @@ void RasterizerStorageGLES3::_update_material(Material *material) { RID texture; + switch (E->get().type) { + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_SAMPLER2DARRAY: { + material->texture_is_3d.write[E->get().texture_order] = true; + } break; + default: { + material->texture_is_3d.write[E->get().texture_order] = false; + } break; + } + Map<StringName, Variant>::Element *V = material->params.find(E->key()); if (V) { texture = V->get(); @@ -2675,6 +2833,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { } else { material->textures.clear(); + material->texture_is_3d.clear(); } } @@ -6999,6 +7158,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { info.texture_mem -= texture->total_data_size; texture_owner.free(p_rid); memdelete(texture); + } else if (sky_owner.owns(p_rid)) { // delete the sky Sky *sky = sky_owner.get(p_rid); @@ -7408,6 +7568,15 @@ void RasterizerStorageGLES3::initialize() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &resources.white_tex_3d); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); } glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index d9c770d1b7..f55c8026ea 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -123,6 +123,8 @@ public: GLuint normal_tex; GLuint aniso_tex; + GLuint white_tex_3d; + GLuint quadie; GLuint quadie_array; @@ -248,9 +250,10 @@ public: String path; uint32_t flags; - int width, height; - int alloc_width, alloc_height; + int width, height, depth; + int alloc_width, alloc_height, alloc_depth; Image::Format format; + VS::TextureType type; GLenum target; GLenum gl_format_cache; @@ -274,7 +277,7 @@ public: RenderTarget *render_target; - Ref<Image> images[6]; + Vector<Ref<Image> > images; VisualServer::TextureDetectCallback detect_3d; void *detect_3d_ud; @@ -340,17 +343,19 @@ public: Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb); virtual RID texture_create(); - virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT); - virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const; + virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); + virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); + virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0); + virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const; virtual void texture_set_flags(RID p_texture, uint32_t p_flags); virtual uint32_t texture_get_flags(RID p_texture) const; virtual Image::Format texture_get_format(RID p_texture) const; + virtual VS::TextureType texture_get_type(RID p_texture) const; virtual uint32_t texture_get_texid(RID p_texture) const; virtual uint32_t texture_get_width(RID p_texture) const; virtual uint32_t texture_get_height(RID p_texture) const; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height); + virtual uint32_t texture_get_depth(RID p_texture) const; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth); virtual void texture_set_path(RID p_texture, const String &p_path); virtual String texture_get_path(RID p_texture) const; @@ -410,6 +415,7 @@ public: Map<StringName, RID> default_textures; + Vector<ShaderLanguage::DataType> texture_types; Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; bool valid; @@ -532,6 +538,7 @@ public: Map<StringName, Variant> params; SelfList<Material> list; SelfList<Material> dirty_list; + Vector<bool> texture_is_3d; Vector<RID> textures; float line_width; int render_priority; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 4ff8c72e13..0c353d42bb 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -341,6 +341,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener r_gen_code.texture_uniforms.resize(max_texture_uniforms); r_gen_code.texture_hints.resize(max_texture_uniforms); + r_gen_code.texture_types.resize(max_texture_uniforms); Vector<int> uniform_sizes; Vector<int> uniform_alignments; @@ -367,6 +368,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener r_gen_code.fragment_global += ucode; r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key()); r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint; + r_gen_code.texture_types.write[E->get().texture_order] = E->get().type; } else { if (!uses_uniforms) { @@ -700,6 +702,11 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) { + if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) { + *p_actions.usage_flag_pointers["DISCARD"] = true; + used_flag_pointers.insert("DISCARD"); + } + code = "discard;"; } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) { diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index bf776ee062..7a32057741 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -52,6 +52,7 @@ public: Vector<CharString> defines; Vector<StringName> texture_uniforms; + Vector<ShaderLanguage::DataType> texture_types; Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints; Vector<uint32_t> uniform_offsets; diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 6fd85cc1dd..dee8bcbc58 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -339,7 +339,7 @@ void main() { #endif #endif - float roughness=0.0; + float roughness = 1.0; //defines that make writing custom shaders easier #define projection_matrix local_projection @@ -1608,18 +1608,18 @@ void main() { //lay out everything, whathever is unused is optimized away anyway highp vec3 vertex = vertex_interp; - vec3 albedo = vec3(0.8,0.8,0.8); + vec3 albedo = vec3(1.0); vec3 transmission = vec3(0.0); float metallic = 0.0; float specular = 0.5; - vec3 emission = vec3(0.0,0.0,0.0); + vec3 emission = vec3(0.0); float roughness = 1.0; float rim = 0.0; float rim_tint = 0.0; - float clearcoat=0.0; - float clearcoat_gloss=0.0; - float anisotropy = 1.0; - vec2 anisotropy_flow = vec2(1.0,0.0); + float clearcoat = 0.0; + float clearcoat_gloss = 0.0; + float anisotropy = 0.0; + vec2 anisotropy_flow = vec2(1.0, 0.0); #if defined(ENABLE_AO) float ao=1.0; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 6db0e58737..d1104eec18 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -64,18 +64,32 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l ad->pa_status++; } +void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) { + AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; + + // If eol is set to a positive number, you're at the end of the list + if (eol > 0) { + return; + } + + ad->pa_rec_map = l->channel_map; + ad->pa_status++; +} + void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) { AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; + ad->capture_default_device = i->default_source_name; ad->default_device = i->default_sink_name; ad->pa_status++; } -void AudioDriverPulseAudio::detect_channels() { +void AudioDriverPulseAudio::detect_channels(bool capture) { - pa_channel_map_init_stereo(&pa_map); + pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map); - if (device_name == "Default") { + String device = capture ? capture_device_name : device_name; + if (device == "Default") { // Get the default output device name pa_status = 0; pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this); @@ -93,16 +107,22 @@ void AudioDriverPulseAudio::detect_channels() { } } - char device[1024]; - if (device_name == "Default") { - strcpy(device, default_device.utf8().get_data()); + char dev[1024]; + if (device == "Default") { + strcpy(dev, capture ? capture_default_device.utf8().get_data() : default_device.utf8().get_data()); } else { - strcpy(device, device_name.utf8().get_data()); + strcpy(dev, device.utf8().get_data()); } // Now using the device name get the amount of channels pa_status = 0; - pa_operation *pa_op = pa_context_get_sink_info_by_name(pa_ctx, device, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this); + pa_operation *pa_op; + if (capture) { + pa_op = pa_context_get_source_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_source_info_cb, (void *)this); + } else { + pa_op = pa_context_get_sink_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this); + } + if (pa_op) { while (pa_status == 0) { int ret = pa_mainloop_iterate(pa_ml, 1, NULL); @@ -113,7 +133,11 @@ void AudioDriverPulseAudio::detect_channels() { pa_operation_unref(pa_op); } else { - ERR_PRINT("pa_context_get_sink_info_by_name error"); + if (capture) { + ERR_PRINT("pa_context_get_source_info_by_name error"); + } else { + ERR_PRINT("pa_context_get_sink_info_by_name error"); + } } } @@ -195,6 +219,10 @@ Error AudioDriverPulseAudio::init_device() { samples_in.resize(buffer_frames * channels); samples_out.resize(pa_buffer_size); + // Reset audio input to keep synchronisation. + input_position = 0; + input_size = 0; + return OK; } @@ -287,74 +315,71 @@ float AudioDriverPulseAudio::get_latency() { void AudioDriverPulseAudio::thread_func(void *p_udata) { AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata; + unsigned int write_ofs = 0; + size_t avail_bytes = 0; while (!ad->exit_thread) { - ad->lock(); - ad->start_counting_ticks(); - - if (!ad->active) { - for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { - ad->samples_out.write[i] = 0; - } + size_t read_bytes = 0; + size_t written_bytes = 0; - } else { - ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); + if (avail_bytes == 0) { + ad->lock(); + ad->start_counting_ticks(); - if (ad->channels == ad->pa_map.channels) { + if (!ad->active) { for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { - ad->samples_out.write[i] = ad->samples_in[i] >> 16; + ad->samples_out.write[i] = 0; } } else { - // Uneven amount of channels - unsigned int in_idx = 0; - unsigned int out_idx = 0; + ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); - for (unsigned int i = 0; i < ad->buffer_frames; i++) { - for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) { - ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16; + if (ad->channels == ad->pa_map.channels) { + for (unsigned int i = 0; i < ad->pa_buffer_size; i++) { + ad->samples_out.write[i] = ad->samples_in[i] >> 16; + } + } else { + // Uneven amount of channels + unsigned int in_idx = 0; + unsigned int out_idx = 0; + + for (unsigned int i = 0; i < ad->buffer_frames; i++) { + for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) { + ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16; + } + uint32_t l = ad->samples_in[in_idx++]; + uint32_t r = ad->samples_in[in_idx++]; + ad->samples_out.write[out_idx++] = ((l >> 1) + (r >> 1)) >> 16; } - uint32_t l = ad->samples_in[in_idx++]; - uint32_t r = ad->samples_in[in_idx++]; - ad->samples_out.write[out_idx++] = (l >> 1 + r >> 1) >> 16; } } + + avail_bytes = ad->pa_buffer_size * sizeof(int16_t); + write_ofs = 0; + ad->stop_counting_ticks(); + ad->unlock(); } - int error_code; - int byte_size = ad->pa_buffer_size * sizeof(int16_t); + ad->lock(); + ad->start_counting_ticks(); + int ret; do { ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL); } while (ret > 0); - if (pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) { - const void *ptr = ad->samples_out.ptr(); - while (byte_size > 0) { - size_t bytes = pa_stream_writable_size(ad->pa_str); - if (bytes > 0) { - if (bytes > byte_size) { - bytes = byte_size; - } - - ret = pa_stream_write(ad->pa_str, ptr, bytes, NULL, 0LL, PA_SEEK_RELATIVE); - if (ret >= 0) { - byte_size -= bytes; - ptr = (const char *)ptr + bytes; - } + if (avail_bytes > 0 && pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) { + size_t bytes = pa_stream_writable_size(ad->pa_str); + if (bytes > 0) { + size_t bytes_to_write = MIN(bytes, avail_bytes); + const void *ptr = ad->samples_out.ptr(); + ret = pa_stream_write(ad->pa_str, (char *)ptr + write_ofs, bytes_to_write, NULL, 0LL, PA_SEEK_RELATIVE); + if (ret != 0) { + ERR_PRINT("pa_stream_write error"); } else { - ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL); - if (ret == 0) { - // If pa_mainloop_iterate returns 0 sleep for 1 msec to wait - // for the stream to be able to process more bytes - ad->stop_counting_ticks(); - ad->unlock(); - - OS::get_singleton()->delay_usec(1000); - - ad->lock(); - ad->start_counting_ticks(); - } + avail_bytes -= bytes_to_write; + write_ofs += bytes_to_write; + written_bytes += bytes_to_write; } } } @@ -379,8 +404,64 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { } } + if (ad->pa_rec_str && pa_stream_get_state(ad->pa_rec_str) == PA_STREAM_READY) { + size_t bytes = pa_stream_readable_size(ad->pa_rec_str); + if (bytes > 0) { + const void *ptr = NULL; + size_t maxbytes = ad->input_buffer.size() * sizeof(int16_t); + + bytes = MIN(bytes, maxbytes); + ret = pa_stream_peek(ad->pa_rec_str, &ptr, &bytes); + if (ret != 0) { + ERR_PRINT("pa_stream_peek error"); + } else { + int16_t *srcptr = (int16_t *)ptr; + for (size_t i = bytes >> 1; i > 0; i--) { + int32_t sample = int32_t(*srcptr++) << 16; + ad->input_buffer_write(sample); + + if (ad->pa_rec_map.channels == 1) { + // In case input device is single channel convert it to Stereo + ad->input_buffer_write(sample); + } + } + + read_bytes += bytes; + ret = pa_stream_drop(ad->pa_rec_str); + if (ret != 0) { + ERR_PRINT("pa_stream_drop error"); + } + } + } + + // User selected a new device, finish the current one so we'll init the new device + if (ad->capture_device_name != ad->capture_new_device) { + ad->capture_device_name = ad->capture_new_device; + ad->capture_finish_device(); + + Error err = ad->capture_init_device(); + if (err != OK) { + ERR_PRINT("PulseAudio: capture_init_device error"); + ad->capture_device_name = "Default"; + ad->capture_new_device = "Default"; + + err = ad->capture_init_device(); + if (err != OK) { + ad->active = false; + ad->exit_thread = true; + break; + } + } + } + } + ad->stop_counting_ticks(); ad->unlock(); + + // Let the thread rest a while if we haven't read or write anything + if (written_bytes == 0 && read_bytes == 0) { + OS::get_singleton()->delay_usec(1000); + } } ad->thread_exited = true; @@ -510,11 +591,165 @@ void AudioDriverPulseAudio::finish() { thread = NULL; } +Error AudioDriverPulseAudio::capture_init_device() { + + // If there is a specified device check that it is really present + if (capture_device_name != "Default") { + Array list = capture_get_device_list(); + if (list.find(capture_device_name) == -1) { + capture_device_name = "Default"; + capture_new_device = "Default"; + } + } + + detect_channels(true); + switch (pa_rec_map.channels) { + case 1: // Mono + case 2: // Stereo + break; + + default: + WARN_PRINTS("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels)); + pa_channel_map_init_stereo(&pa_rec_map); + break; + } + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels"); + } + + pa_sample_spec spec; + + spec.format = PA_SAMPLE_S16LE; + spec.channels = pa_rec_map.channels; + spec.rate = mix_rate; + + int latency = 30; + input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000); + int buffer_size = input_buffer_frames * spec.channels; + + pa_buffer_attr attr; + attr.fragsize = buffer_size * sizeof(int16_t); + + pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map); + if (pa_rec_str == NULL) { + ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx)))); + ERR_FAIL_V(ERR_CANT_OPEN); + } + + const char *dev = capture_device_name == "Default" ? NULL : capture_device_name.utf8().get_data(); + pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); + int error_code = pa_stream_connect_record(pa_rec_str, dev, &attr, flags); + if (error_code < 0) { + ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code))); + ERR_FAIL_V(ERR_CANT_OPEN); + } + + input_buffer.resize(input_buffer_frames * 8); + input_position = 0; + input_size = 0; + + return OK; +} + +void AudioDriverPulseAudio::capture_finish_device() { + + if (pa_rec_str) { + int ret = pa_stream_disconnect(pa_rec_str); + if (ret != 0) { + ERR_PRINTS("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret))); + } + pa_stream_unref(pa_rec_str); + pa_rec_str = NULL; + } +} + +Error AudioDriverPulseAudio::capture_start() { + + lock(); + Error err = capture_init_device(); + unlock(); + + return err; +} + +Error AudioDriverPulseAudio::capture_stop() { + lock(); + capture_finish_device(); + unlock(); + + return OK; +} + +void AudioDriverPulseAudio::capture_set_device(const String &p_name) { + + lock(); + capture_new_device = p_name; + unlock(); +} + +void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) { + AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; + + // If eol is set to a positive number, you're at the end of the list + if (eol > 0) { + return; + } + + if (l->monitor_of_sink == PA_INVALID_INDEX) { + ad->pa_rec_devices.push_back(l->name); + } + + ad->pa_status++; +} + +Array AudioDriverPulseAudio::capture_get_device_list() { + + pa_rec_devices.clear(); + pa_rec_devices.push_back("Default"); + + if (pa_ctx == NULL) { + return pa_rec_devices; + } + + lock(); + + // Get the device list + pa_status = 0; + pa_operation *pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, (void *)this); + if (pa_op) { + while (pa_status == 0) { + int ret = pa_mainloop_iterate(pa_ml, 1, NULL); + if (ret < 0) { + ERR_PRINT("pa_mainloop_iterate error"); + } + } + + pa_operation_unref(pa_op); + } else { + ERR_PRINT("pa_context_get_server_info error"); + } + + unlock(); + + return pa_rec_devices; +} + +String AudioDriverPulseAudio::capture_get_device() { + + lock(); + String name = capture_device_name; + unlock(); + + return name; +} + AudioDriverPulseAudio::AudioDriverPulseAudio() { pa_ml = NULL; pa_ctx = NULL; pa_str = NULL; + pa_rec_str = NULL; mutex = NULL; thread = NULL; @@ -528,6 +763,7 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() { mix_rate = 0; buffer_frames = 0; + input_buffer_frames = 0; pa_buffer_size = 0; channels = 0; pa_ready = 0; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index b471f5f9d5..f8358a452b 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -47,22 +47,30 @@ class AudioDriverPulseAudio : public AudioDriver { pa_mainloop *pa_ml; pa_context *pa_ctx; pa_stream *pa_str; + pa_stream *pa_rec_str; pa_channel_map pa_map; + pa_channel_map pa_rec_map; String device_name; String new_device; String default_device; + String capture_device_name; + String capture_new_device; + String capture_default_device; + Vector<int32_t> samples_in; Vector<int16_t> samples_out; unsigned int mix_rate; unsigned int buffer_frames; + unsigned int input_buffer_frames; unsigned int pa_buffer_size; int channels; int pa_ready; int pa_status; Array pa_devices; + Array pa_rec_devices; bool active; bool thread_exited; @@ -72,13 +80,18 @@ class AudioDriverPulseAudio : public AudioDriver { static void pa_state_cb(pa_context *c, void *userdata); static void pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata); + static void pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata); static void pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata); static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata); + static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata); Error init_device(); void finish_device(); - void detect_channels(); + Error capture_init_device(); + void capture_finish_device(); + + void detect_channels(bool capture = false); static void thread_func(void *p_udata); @@ -91,15 +104,24 @@ public: virtual void start(); virtual int get_mix_rate() const; virtual SpeakerMode get_speaker_mode() const; + virtual Array get_device_list(); virtual String get_device(); virtual void set_device(String device); + + virtual Array capture_get_device_list(); + virtual void capture_set_device(const String &p_name); + virtual String capture_get_device(); + virtual void lock(); virtual void unlock(); virtual void finish(); virtual float get_latency(); + virtual Error capture_start(); + virtual Error capture_stop(); + AudioDriverPulseAudio(); ~AudioDriverPulseAudio(); }; diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 5982955c4f..2dcb4ff3d8 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -52,8 +52,22 @@ const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); const IID IID_IAudioClient = __uuidof(IAudioClient); const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); +const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient); -static bool default_device_changed = false; +#define SAFE_RELEASE(memory) \ + if ((memory) != NULL) { \ + (memory)->Release(); \ + (memory) = NULL; \ + } + +#define REFTIMES_PER_SEC 10000000 +#define REFTIMES_PER_MILLISEC 10000 + +#define CAPTURE_BUFFER_CHANNELS 2 + +static StringName capture_device_id; +static bool default_render_device_changed = false; +static bool default_capture_device_changed = false; class CMMNotificationClient : public IMMNotificationClient { LONG _cRef; @@ -109,8 +123,13 @@ public: } HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) { - if (flow == eRender && role == eConsole) { - default_device_changed = true; + if (role == eConsole) { + if (flow == eRender) { + default_render_device_changed = true; + } else if (flow == eCapture) { + default_capture_device_changed = true; + capture_device_id = String(pwstrDeviceId); + } } return S_OK; @@ -123,7 +142,7 @@ public: static CMMNotificationClient notif_client; -Error AudioDriverWASAPI::init_device(bool reinit) { +Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) { WAVEFORMATEX *pwfex; IMMDeviceEnumerator *enumerator = NULL; @@ -134,12 +153,12 @@ Error AudioDriverWASAPI::init_device(bool reinit) { HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - if (device_name == "Default") { - hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); + if (p_device->device_name == "Default") { + hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device); } else { IMMDeviceCollection *devices = NULL; - hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices); + hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); LPWSTR strId = NULL; @@ -165,7 +184,7 @@ Error AudioDriverWASAPI::init_device(bool reinit) { hr = props->GetValue(PKEY_Device_FriendlyName, &propvar); ERR_BREAK(hr != S_OK); - if (device_name == String(propvar.pwszVal)) { + if (p_device->device_name == String(propvar.pwszVal)) { hr = device->GetId(&strId); ERR_BREAK(hr != S_OK); @@ -186,9 +205,10 @@ Error AudioDriverWASAPI::init_device(bool reinit) { } if (device == NULL) { - hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device); + hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device); } } + if (reinit) { // In case we're trying to re-initialize the device prevent throwing this error on the console, // otherwise if there is currently no device available this will spam the console. @@ -200,11 +220,15 @@ Error AudioDriverWASAPI::init_device(bool reinit) { } hr = enumerator->RegisterEndpointNotificationCallback(¬if_client); + SAFE_RELEASE(enumerator) + if (hr != S_OK) { ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error"); } - hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client); + hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&p_device->audio_client); + SAFE_RELEASE(device) + if (reinit) { if (hr != S_OK) { return ERR_CANT_OPEN; @@ -213,75 +237,89 @@ Error AudioDriverWASAPI::init_device(bool reinit) { ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); } - hr = audio_client->GetMixFormat(&pwfex); + hr = p_device->audio_client->GetMixFormat(&pwfex); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along - wasapi_channels = pwfex->nChannels; - format_tag = pwfex->wFormatTag; - bits_per_sample = pwfex->wBitsPerSample; + p_device->channels = pwfex->nChannels; + p_device->format_tag = pwfex->wFormatTag; + p_device->bits_per_sample = pwfex->wBitsPerSample; + p_device->frame_size = (p_device->bits_per_sample / 8) * p_device->channels; - switch (wasapi_channels) { - case 2: // Stereo - case 4: // Surround 3.1 - case 6: // Surround 5.1 - case 8: // Surround 7.1 - channels = wasapi_channels; - break; - - default: - WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(wasapi_channels)); - channels = 2; - break; - } - - if (format_tag == WAVE_FORMAT_EXTENSIBLE) { + if (p_device->format_tag == WAVE_FORMAT_EXTENSIBLE) { WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex; if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) { - format_tag = WAVE_FORMAT_PCM; + p_device->format_tag = WAVE_FORMAT_PCM; } else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) { - format_tag = WAVE_FORMAT_IEEE_FLOAT; + p_device->format_tag = WAVE_FORMAT_IEEE_FLOAT; } else { ERR_PRINT("WASAPI: Format not supported"); ERR_FAIL_V(ERR_CANT_OPEN); } } else { - if (format_tag != WAVE_FORMAT_PCM && format_tag != WAVE_FORMAT_IEEE_FLOAT) { + if (p_device->format_tag != WAVE_FORMAT_PCM && p_device->format_tag != WAVE_FORMAT_IEEE_FLOAT) { ERR_PRINT("WASAPI: Format not supported"); ERR_FAIL_V(ERR_CANT_OPEN); } } - DWORD streamflags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK; + DWORD streamflags = 0; if (mix_rate != pwfex->nSamplesPerSec) { streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST; pwfex->nSamplesPerSec = mix_rate; pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8); } - hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, 0, 0, pwfex, NULL); + hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - event = CreateEvent(NULL, FALSE, FALSE, NULL); - ERR_FAIL_COND_V(event == NULL, ERR_CANT_OPEN); - - hr = audio_client->SetEventHandle(event); + if (p_capture) { + hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client); + } else { + hr = p_device->audio_client->GetService(IID_IAudioRenderClient, (void **)&p_device->render_client); + } ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client); - ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + // Free memory + CoTaskMemFree(pwfex); + SAFE_RELEASE(device) + + return OK; +} + +Error AudioDriverWASAPI::init_render_device(bool reinit) { + + Error err = audio_device_init(&audio_output, false, reinit); + if (err != OK) + return err; + + switch (audio_output.channels) { + case 2: // Stereo + case 4: // Surround 3.1 + case 6: // Surround 5.1 + case 8: // Surround 7.1 + channels = audio_output.channels; + break; + + default: + WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(audio_output.channels)); + channels = 2; + break; + } UINT32 max_frames; - hr = audio_client->GetBufferSize(&max_frames); + HRESULT hr = audio_output.audio_client->GetBufferSize(&max_frames); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); // Due to WASAPI Shared Mode we have no control of the buffer size buffer_frames = max_frames; // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) - buffer_size = buffer_frames * channels; - samples_in.resize(buffer_size); + samples_in.resize(buffer_frames * channels); + + input_position = 0; + input_size = 0; if (OS::get_singleton()->is_stdout_verbose()) { print_line("WASAPI: detected " + itos(channels) + " channels"); @@ -291,41 +329,61 @@ Error AudioDriverWASAPI::init_device(bool reinit) { return OK; } -Error AudioDriverWASAPI::finish_device() { +Error AudioDriverWASAPI::init_capture_device(bool reinit) { - if (audio_client) { - if (active) { - audio_client->Stop(); - active = false; - } + Error err = audio_device_init(&audio_input, true, reinit); + if (err != OK) + return err; - audio_client->Release(); - audio_client = NULL; - } + // Get the max frames + UINT32 max_frames; + HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames); + ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - if (render_client) { - render_client->Release(); - render_client = NULL; - } + // Set the buffer size + input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS); + input_position = 0; + input_size = 0; - if (audio_client) { - audio_client->Release(); - audio_client = NULL; + return OK; +} + +Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) { + + if (p_device->active) { + if (p_device->audio_client) { + p_device->audio_client->Stop(); + } + + p_device->active = false; } + SAFE_RELEASE(p_device->audio_client) + SAFE_RELEASE(p_device->render_client) + SAFE_RELEASE(p_device->capture_client) + return OK; } +Error AudioDriverWASAPI::finish_render_device() { + + return audio_device_finish(&audio_output); +} + +Error AudioDriverWASAPI::finish_capture_device() { + + return audio_device_finish(&audio_input); +} + Error AudioDriverWASAPI::init() { mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); - Error err = init_device(); + Error err = init_render_device(); if (err != OK) { - ERR_PRINT("WASAPI: init_device error"); + ERR_PRINT("WASAPI: init_render_device error"); } - active = false; exit_thread = false; thread_exited = false; @@ -345,7 +403,7 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { return get_speaker_mode_by_total_channels(channels); } -Array AudioDriverWASAPI::get_device_list() { +Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) { Array list; IMMDeviceCollection *devices = NULL; @@ -358,7 +416,7 @@ Array AudioDriverWASAPI::get_device_list() { HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); ERR_FAIL_COND_V(hr != S_OK, Array()); - hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices); + hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices); ERR_FAIL_COND_V(hr != S_OK, Array()); UINT count = 0; @@ -393,21 +451,63 @@ Array AudioDriverWASAPI::get_device_list() { return list; } +Array AudioDriverWASAPI::get_device_list() { + + return audio_device_get_list(false); +} + String AudioDriverWASAPI::get_device() { - return device_name; + lock(); + String name = audio_output.device_name; + unlock(); + + return name; } void AudioDriverWASAPI::set_device(String device) { lock(); - new_device = device; + audio_output.new_device = device; unlock(); } -void AudioDriverWASAPI::write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i, int32_t sample) { - if (ad->format_tag == WAVE_FORMAT_PCM) { - switch (ad->bits_per_sample) { +int32_t AudioDriverWASAPI::read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i) { + if (format_tag == WAVE_FORMAT_PCM) { + int32_t sample = 0; + switch (bits_per_sample) { + case 8: + sample = int32_t(((int8_t *)buffer)[i]) << 24; + break; + + case 16: + sample = int32_t(((int16_t *)buffer)[i]) << 16; + break; + + case 24: + sample |= int32_t(((int8_t *)buffer)[i * 3 + 2]) << 24; + sample |= int32_t(((int8_t *)buffer)[i * 3 + 1]) << 16; + sample |= int32_t(((int8_t *)buffer)[i * 3 + 0]) << 8; + break; + + case 32: + sample = ((int32_t *)buffer)[i]; + break; + } + + return sample; + } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) { + return int32_t(((float *)buffer)[i] * 32768.0) << 16; + } else { + ERR_PRINT("WASAPI: Unknown format tag"); + } + + return 0; +} + +void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample) { + if (format_tag == WAVE_FORMAT_PCM) { + switch (bits_per_sample) { case 8: ((int8_t *)buffer)[i] = sample >> 24; break; @@ -426,83 +526,99 @@ void AudioDriverWASAPI::write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i, ((int32_t *)buffer)[i] = sample; break; } - } else if (ad->format_tag == WAVE_FORMAT_IEEE_FLOAT) { + } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) { ((float *)buffer)[i] = (sample >> 16) / 32768.f; } else { ERR_PRINT("WASAPI: Unknown format tag"); - ad->exit_thread = true; } } void AudioDriverWASAPI::thread_func(void *p_udata) { AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata; + uint32_t avail_frames = 0; + uint32_t write_ofs = 0; while (!ad->exit_thread) { - ad->lock(); - ad->start_counting_ticks(); + uint32_t read_frames = 0; + uint32_t written_frames = 0; - if (ad->active) { - ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); - } else { - for (unsigned int i = 0; i < ad->buffer_size; i++) { - ad->samples_in.write[i] = 0; + if (avail_frames == 0) { + ad->lock(); + ad->start_counting_ticks(); + + if (ad->audio_output.active) { + ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); + } else { + for (unsigned int i = 0; i < ad->samples_in.size(); i++) { + ad->samples_in.write[i] = 0; + } } - } - ad->stop_counting_ticks(); - ad->unlock(); + avail_frames = ad->buffer_frames; + write_ofs = 0; - unsigned int left_frames = ad->buffer_frames; - unsigned int buffer_idx = 0; - while (left_frames > 0 && ad->audio_client) { - WaitForSingleObject(ad->event, 1000); + ad->stop_counting_ticks(); + ad->unlock(); + } - ad->lock(); - ad->start_counting_ticks(); + ad->lock(); + ad->start_counting_ticks(); + + if (avail_frames > 0 && ad->audio_output.audio_client) { UINT32 cur_frames; bool invalidated = false; - HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames); + HRESULT hr = ad->audio_output.audio_client->GetCurrentPadding(&cur_frames); if (hr == S_OK) { - // Check how much frames are available on the WASAPI buffer - UINT32 avail_frames = ad->buffer_frames - cur_frames; - UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames; - BYTE *buffer = NULL; - hr = ad->render_client->GetBuffer(write_frames, &buffer); - if (hr == S_OK) { - // We're using WASAPI Shared Mode so we must convert the buffer - - if (ad->channels == ad->wasapi_channels) { - for (unsigned int i = 0; i < write_frames * ad->channels; i++) { - ad->write_sample(ad, buffer, i, ad->samples_in[buffer_idx++]); - } - } else { - for (unsigned int i = 0; i < write_frames; i++) { - for (unsigned int j = 0; j < MIN(ad->channels, ad->wasapi_channels); j++) { - ad->write_sample(ad, buffer, i * ad->wasapi_channels + j, ad->samples_in[buffer_idx++]); + // Check how much frames are available on the WASAPI buffer + UINT32 write_frames = MIN(ad->buffer_frames - cur_frames, avail_frames); + if (write_frames > 0) { + BYTE *buffer = NULL; + hr = ad->audio_output.render_client->GetBuffer(write_frames, &buffer); + if (hr == S_OK) { + + // We're using WASAPI Shared Mode so we must convert the buffer + if (ad->channels == ad->audio_output.channels) { + for (unsigned int i = 0; i < write_frames * ad->channels; i++) { + ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i, ad->samples_in.write[write_ofs++]); } - if (ad->wasapi_channels > ad->channels) { - for (unsigned int j = ad->channels; j < ad->wasapi_channels; j++) { - ad->write_sample(ad, buffer, i * ad->wasapi_channels + j, 0); + } else { + for (unsigned int i = 0; i < write_frames; i++) { + for (unsigned int j = 0; j < MIN(ad->channels, ad->audio_output.channels); j++) { + ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, ad->samples_in.write[write_ofs++]); + } + if (ad->audio_output.channels > ad->channels) { + for (unsigned int j = ad->channels; j < ad->audio_output.channels; j++) { + ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, 0); + } } } } - } - hr = ad->render_client->ReleaseBuffer(write_frames, 0); - if (hr != S_OK) { - ERR_PRINT("WASAPI: Release buffer error"); - } + hr = ad->audio_output.render_client->ReleaseBuffer(write_frames, 0); + if (hr != S_OK) { + ERR_PRINT("WASAPI: Release buffer error"); + } - left_frames -= write_frames; - } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { - invalidated = true; - } else { - ERR_PRINT("WASAPI: Get buffer error"); - ad->exit_thread = true; + avail_frames -= write_frames; + written_frames += write_frames; + } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { + // Device is not valid anymore, reopen it + + Error err = ad->finish_render_device(); + if (err != OK) { + ERR_PRINT("WASAPI: finish_render_device error"); + } else { + // We reopened the device and samples_in may have resized, so invalidate the current avail_frames + avail_frames = 0; + } + } else { + ERR_PRINT("WASAPI: Get buffer error"); + ad->exit_thread = true; + } } } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) { invalidated = true; @@ -514,47 +630,117 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { // Device is not valid anymore WARN_PRINT("WASAPI: Current device invalidated, closing device"); - Error err = ad->finish_device(); + Error err = ad->finish_render_device(); if (err != OK) { - ERR_PRINT("WASAPI: finish_device error"); + ERR_PRINT("WASAPI: finish_render_device error"); } } - - ad->stop_counting_ticks(); - ad->unlock(); } - ad->lock(); - ad->start_counting_ticks(); - // If we're using the Default device and it changed finish it so we'll re-init the device - if (ad->device_name == "Default" && default_device_changed) { - Error err = ad->finish_device(); + if (ad->audio_output.device_name == "Default" && default_render_device_changed) { + Error err = ad->finish_render_device(); if (err != OK) { - ERR_PRINT("WASAPI: finish_device error"); + ERR_PRINT("WASAPI: finish_render_device error"); } - default_device_changed = false; + default_render_device_changed = false; } // User selected a new device, finish the current one so we'll init the new device - if (ad->device_name != ad->new_device) { - ad->device_name = ad->new_device; - Error err = ad->finish_device(); + if (ad->audio_output.device_name != ad->audio_output.new_device) { + ad->audio_output.device_name = ad->audio_output.new_device; + Error err = ad->finish_render_device(); if (err != OK) { - ERR_PRINT("WASAPI: finish_device error"); + ERR_PRINT("WASAPI: finish_render_device error"); } } - if (!ad->audio_client) { - Error err = ad->init_device(true); + if (!ad->audio_output.audio_client) { + Error err = ad->init_render_device(true); if (err == OK) { ad->start(); } } + if (ad->audio_input.active) { + UINT32 packet_length = 0; + BYTE *data; + UINT32 num_frames_available; + DWORD flags; + + HRESULT hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length); + if (hr == S_OK) { + while (packet_length != 0) { + hr = ad->audio_input.capture_client->GetBuffer(&data, &num_frames_available, &flags, NULL, NULL); + ERR_BREAK(hr != S_OK); + + // fixme: Only works for floating point atm + for (int j = 0; j < num_frames_available; j++) { + int32_t l, r; + + if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { + l = r = 0; + } else { + if (ad->audio_input.channels == 2) { + l = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2); + r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2 + 1); + } else if (ad->audio_input.channels == 1) { + l = r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j); + } else { + l = r = 0; + ERR_PRINT("WASAPI: unsupported channel count in microphone!"); + } + } + + ad->input_buffer_write(l); + ad->input_buffer_write(r); + } + + read_frames += num_frames_available; + + hr = ad->audio_input.capture_client->ReleaseBuffer(num_frames_available); + ERR_BREAK(hr != S_OK); + + hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length); + ERR_BREAK(hr != S_OK); + } + } + + // If we're using the Default device and it changed finish it so we'll re-init the device + if (ad->audio_input.device_name == "Default" && default_capture_device_changed) { + Error err = ad->finish_capture_device(); + if (err != OK) { + ERR_PRINT("WASAPI: finish_capture_device error"); + } + + default_capture_device_changed = false; + } + + // User selected a new device, finish the current one so we'll init the new device + if (ad->audio_input.device_name != ad->audio_input.new_device) { + ad->audio_input.device_name = ad->audio_input.new_device; + Error err = ad->finish_capture_device(); + if (err != OK) { + ERR_PRINT("WASAPI: finish_capture_device error"); + } + } + + if (!ad->audio_input.audio_client) { + Error err = ad->init_capture_device(true); + if (err == OK) { + ad->capture_start(); + } + } + } + ad->stop_counting_ticks(); ad->unlock(); + + // Let the thread rest a while if we haven't read or write anything + if (written_frames == 0 && read_frames == 0) { + OS::get_singleton()->delay_usec(1000); + } } ad->thread_exited = true; @@ -562,12 +748,12 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { void AudioDriverWASAPI::start() { - if (audio_client) { - HRESULT hr = audio_client->Start(); + if (audio_output.audio_client) { + HRESULT hr = audio_output.audio_client->Start(); if (hr != S_OK) { ERR_PRINT("WASAPI: Start failed"); } else { - active = true; + audio_output.active = true; } } } @@ -594,7 +780,8 @@ void AudioDriverWASAPI::finish() { thread = NULL; } - finish_device(); + finish_capture_device(); + finish_render_device(); if (mutex) { memdelete(mutex); @@ -602,30 +789,70 @@ void AudioDriverWASAPI::finish() { } } +Error AudioDriverWASAPI::capture_start() { + + Error err = init_capture_device(); + if (err != OK) { + ERR_PRINT("WASAPI: init_capture_device error"); + return err; + } + + if (audio_input.active == false) { + audio_input.audio_client->Start(); + audio_input.active = true; + + return OK; + } + + return FAILED; +} + +Error AudioDriverWASAPI::capture_stop() { + + if (audio_input.active == true) { + audio_input.audio_client->Stop(); + audio_input.active = false; + + return OK; + } + + return FAILED; +} + +void AudioDriverWASAPI::capture_set_device(const String &p_name) { + + lock(); + audio_input.new_device = p_name; + unlock(); +} + +Array AudioDriverWASAPI::capture_get_device_list() { + + return audio_device_get_list(true); +} + +String AudioDriverWASAPI::capture_get_device() { + + lock(); + String name = audio_input.device_name; + unlock(); + + return name; +} + AudioDriverWASAPI::AudioDriverWASAPI() { - audio_client = NULL; - render_client = NULL; mutex = NULL; thread = NULL; - format_tag = 0; - bits_per_sample = 0; - samples_in.clear(); - buffer_size = 0; channels = 0; - wasapi_channels = 0; mix_rate = 0; buffer_frames = 0; thread_exited = false; exit_thread = false; - active = false; - - device_name = "Default"; - new_device = "Default"; } #endif diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index f3ee5976eb..3d94f3ba49 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -43,35 +43,63 @@ class AudioDriverWASAPI : public AudioDriver { - HANDLE event; - IAudioClient *audio_client; - IAudioRenderClient *render_client; + class AudioDeviceWASAPI { + public: + IAudioClient *audio_client; + IAudioRenderClient *render_client; + IAudioCaptureClient *capture_client; + bool active; + + WORD format_tag; + WORD bits_per_sample; + unsigned int channels; + unsigned int frame_size; + + String device_name; + String new_device; + + AudioDeviceWASAPI() { + audio_client = NULL; + render_client = NULL; + capture_client = NULL; + active = false; + format_tag = 0; + bits_per_sample = 0; + channels = 0; + frame_size = 0; + device_name = "Default"; + new_device = "Default"; + } + }; + + AudioDeviceWASAPI audio_input; + AudioDeviceWASAPI audio_output; + Mutex *mutex; Thread *thread; - String device_name; - String new_device; - - WORD format_tag; - WORD bits_per_sample; - Vector<int32_t> samples_in; - unsigned int buffer_size; unsigned int channels; - unsigned int wasapi_channels; int mix_rate; int buffer_frames; bool thread_exited; mutable bool exit_thread; - bool active; - _FORCE_INLINE_ void write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i, int32_t sample); + static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample); + static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i); static void thread_func(void *p_udata); - Error init_device(bool reinit = false); - Error finish_device(); + Error init_render_device(bool reinit = false); + Error init_capture_device(bool reinit = false); + + Error finish_render_device(); + Error finish_capture_device(); + + Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit); + Error audio_device_finish(AudioDeviceWASAPI *p_device); + Array audio_device_get_list(bool p_capture); public: virtual const char *get_name() const { @@ -89,6 +117,12 @@ public: virtual void unlock(); virtual void finish(); + virtual Error capture_start(); + virtual Error capture_stop(); + virtual Array capture_get_device_list(); + virtual void capture_set_device(const String &p_name); + virtual String capture_get_device(); + AudioDriverWASAPI(); }; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 4ce8556add..9d4333bc29 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -745,7 +745,7 @@ bool CodeTextEditor::_add_font_size(int p_delta) { if (font.is_valid()) { int new_size = CLAMP(font->get_size() + p_delta, 8 * EDSCALE, 96 * EDSCALE); - zoom_nb->set_text(itos(100 * new_size / 14) + "%"); + zoom_nb->set_text(itos(100 * new_size / (14 * EDSCALE)) + "%"); if (new_size != font->get_size()) { EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE); @@ -1246,6 +1246,29 @@ CodeTextEditor::CodeTextEditor() { status_bar->add_child(memnew(Label)); //to keep the height if the other labels are not visible + warning_label = memnew(Label); + status_bar->add_child(warning_label); + warning_label->set_align(Label::ALIGN_RIGHT); + warning_label->set_valign(Label::VALIGN_CENTER); + warning_label->set_v_size_flags(SIZE_FILL); + warning_label->set_default_cursor_shape(CURSOR_POINTING_HAND); + warning_label->set_mouse_filter(MOUSE_FILTER_STOP); + warning_label->set_text(TTR("Warnings:")); + warning_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + + warning_count_label = memnew(Label); + status_bar->add_child(warning_count_label); + warning_count_label->set_valign(Label::VALIGN_CENTER); + warning_count_label->set_v_size_flags(SIZE_FILL); + warning_count_label->set_autowrap(true); // workaround to prevent resizing the label on each change, do not touch + warning_count_label->set_clip_text(true); // workaround to prevent resizing the label on each change, do not touch + warning_count_label->set_custom_minimum_size(Size2(40, 1) * EDSCALE); + warning_count_label->set_align(Label::ALIGN_RIGHT); + warning_count_label->set_default_cursor_shape(CURSOR_POINTING_HAND); + warning_count_label->set_mouse_filter(MOUSE_FILTER_STOP); + warning_count_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + warning_count_label->set_text("0"); + Label *zoom_txt = memnew(Label); status_bar->add_child(zoom_txt); zoom_txt->set_align(Label::ALIGN_RIGHT); @@ -1318,7 +1341,7 @@ CodeTextEditor::CodeTextEditor() { font_resize_val = 0; font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - zoom_nb->set_text(itos(100 * font_size / 14) + "%"); + zoom_nb->set_text(itos(100 * font_size / (14 * EDSCALE)) + "%"); font_resize_timer = memnew(Timer); add_child(font_resize_timer); font_resize_timer->set_one_shot(true); diff --git a/editor/code_editor.h b/editor/code_editor.h index 903f61d87d..ee47eff9a8 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -142,6 +142,8 @@ class CodeTextEditor : public VBoxContainer { TextEdit *text_editor; FindReplaceBar *find_replace_bar; HBoxContainer *status_bar; + Label *warning_label; + Label *warning_count_label; Label *line_nb; Label *col_nb; @@ -214,6 +216,8 @@ public: void update_line_and_column() { _line_col_changed(); } TextEdit *get_text_edit() { return text_editor; } FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } + Label *get_warning_label() const { return warning_label; } + Label *get_warning_count_label() const { return warning_count_label; } virtual void apply_code() {} void set_code_complete_func(CodeTextEditorCodeCompleteFunc p_code_complete_func, void *p_ud); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 3e0c1f2d53..5dd5b7fcc5 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -86,7 +86,7 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode) { memdelete(f); } - _update_favorite_list(); + _save_and_update_favorite_list(); // Restore valid window bounds or pop up at default size. if (EditorSettings::get_singleton()->has_setting("interface/dialogs/create_new_node_bounds")) { @@ -425,6 +425,8 @@ void CreateDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { connect("confirmed", this, "_confirmed"); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); favorite->set_icon(get_icon("Favorites", "EditorIcons")); } break; case NOTIFICATION_EXIT_TREE: { @@ -543,8 +545,7 @@ void CreateDialog::_favorite_toggled() { favorite->set_pressed(false); } - _save_favorite_list(); - _update_favorite_list(); + _save_and_update_favorite_list(); } void CreateDialog::_save_favorite_list() { @@ -554,8 +555,11 @@ void CreateDialog::_save_favorite_list() { if (f) { for (int i = 0; i < favorite_list.size(); i++) { - - f->store_line(favorite_list[i]); + String l = favorite_list[i]; + String name = l.split(" ")[0]; + if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) + continue; + f->store_line(l); } memdelete(f); } @@ -566,11 +570,15 @@ void CreateDialog::_update_favorite_list() { favorites->clear(); TreeItem *root = favorites->create_item(); for (int i = 0; i < favorite_list.size(); i++) { - TreeItem *ti = favorites->create_item(root); String l = favorite_list[i]; + String name = l.split(" ")[0]; + if (!(ClassDB::class_exists(name) || ScriptServer::is_global_class(name))) + continue; + TreeItem *ti = favorites->create_item(root); ti->set_text(0, l); ti->set_icon(0, _get_editor_icon(l)); } + emit_signal("favorites_updated"); } void CreateDialog::_history_selected() { @@ -673,6 +681,10 @@ void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co } } + _save_and_update_favorite_list(); +} + +void CreateDialog::_save_and_update_favorite_list() { _save_favorite_list(); _update_favorite_list(); } @@ -688,12 +700,14 @@ void CreateDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_favorite_selected"), &CreateDialog::_favorite_selected); ClassDB::bind_method(D_METHOD("_history_activated"), &CreateDialog::_history_activated); ClassDB::bind_method(D_METHOD("_favorite_activated"), &CreateDialog::_favorite_activated); + ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list); ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw); ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw); ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw); ADD_SIGNAL(MethodInfo("create")); + ADD_SIGNAL(MethodInfo("favorites_updated")); } CreateDialog::CreateDialog() { diff --git a/editor/create_dialog.h b/editor/create_dialog.h index f8eec231a4..6df9eebc8c 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -90,6 +90,8 @@ protected: void _notification(int p_what); static void _bind_methods(); + void _save_and_update_favorite_list(); + public: Object *instance_selected(); String get_selected_type(); diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 2803762973..91a29f5717 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -535,13 +535,14 @@ void DocData::generate(bool p_basic_types) { } List<StringName> constants; - Variant::get_numeric_constants_for_type(Variant::Type(i), &constants); + Variant::get_constants_for_type(Variant::Type(i), &constants); for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { ConstantDoc constant; constant.name = E->get(); - constant.value = itos(Variant::get_numeric_constant_value(Variant::Type(i), E->get())); + Variant value = Variant::get_constant_value(Variant::Type(i), E->get()); + constant.value = value.get_type() == Variant::INT ? itos(value) : value.get_construct_string(); c.constants.push_back(constant); } } diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 4b09db0a9e..e4602f0f94 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -113,7 +113,7 @@ ScrollContainer *EditorAbout::_populate_list(const String &p_name, const List<St EditorAbout::EditorAbout() { set_title(TTR("Thanks from the Godot community!")); - get_ok()->set_text(TTR("Thanks!")); + get_ok()->set_text(TTR("OK")); set_hide_on_ok(true); set_resizable(true); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 7d56c4985a..d240f4ed25 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -558,7 +558,9 @@ void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p } if (single_item_selected) { item_menu->add_separator(); - item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + Dictionary item_meta = item_list->get_item_metadata(p_item); + String item_text = item_meta["dir"] ? TTR("Open In File Manager") : TTR("Show In File Manager"); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), item_text, ITEM_MENU_SHOW_IN_EXPLORER); } if (item_menu->get_item_count() > 0) { @@ -582,7 +584,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) { } item_menu->add_icon_item(get_icon("Reload", "EditorIcons"), TTR("Refresh"), ITEM_MENU_REFRESH, KEY_F5); item_menu->add_separator(); - item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Show In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); + item_menu->add_icon_item(get_icon("Filesystem", "EditorIcons"), TTR("Open In File Manager"), ITEM_MENU_SHOW_IN_EXPLORER); item_menu->set_position(item_list->get_global_position() + p_pos); item_menu->popup(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index d8ab41fa05..671ac755b2 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1366,6 +1366,7 @@ void EditorFileSystem::update_script_classes() { } ScriptServer::save_global_classes(); + emit_signal("script_classes_updated"); } void EditorFileSystem::_queue_update_script_classes() { @@ -1704,6 +1705,7 @@ void EditorFileSystem::_bind_methods() { ADD_SIGNAL(MethodInfo("filesystem_changed")); ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist"))); ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::POOL_STRING_ARRAY, "resources"))); + ADD_SIGNAL(MethodInfo("script_classes_updated")); } void EditorFileSystem::_update_extensions() { diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 727383b960..60826aa81b 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -253,7 +253,8 @@ void EditorHelpSearch::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); connect("confirmed", this, "_confirmed"); _update_search(); @@ -267,7 +268,8 @@ void EditorHelpSearch::_notification(int p_what) { } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } else if (p_what == NOTIFICATION_PROCESS) { if (search.is_valid()) { @@ -381,7 +383,8 @@ void EditorHelpIndex::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); _update_class_list(); connect("confirmed", this, "_tree_item_selected"); @@ -392,7 +395,8 @@ void EditorHelpIndex::_notification(int p_what) { } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { //_update_icons - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } } @@ -541,6 +545,7 @@ void EditorHelp::_class_desc_select(const String &p_select) { String class_name; if (select.find(".") != -1) { class_name = select.get_slice(".", 0); + select = select.get_slice(".", 1); } else { class_name = "@GlobalScope"; } @@ -713,16 +718,22 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { if (p_class == edited_class) return OK; //already there + edited_class = p_class; + _update_doc(); + return OK; +} + +void EditorHelp::_update_doc() { + scroll_locked = true; class_desc->clear(); method_line.clear(); section_line.clear(); - edited_class = p_class; _init_colors(); - DocData::ClassDoc cd = doc->class_list[p_class]; //make a copy, so we can sort without worrying + DocData::ClassDoc cd = doc->class_list[edited_class]; //make a copy, so we can sort without worrying Ref<Font> doc_font = get_font("doc", "EditorFonts"); Ref<Font> doc_title_font = get_font("doc_title", "EditorFonts"); @@ -734,7 +745,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_color(title_color); class_desc->add_text(TTR("Class:") + " "); class_desc->push_color(headline_color); - _add_text(p_class); + _add_text(edited_class); class_desc->pop(); class_desc->pop(); class_desc->pop(); @@ -1214,6 +1225,18 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { constant_line[constants[i].name] = class_desc->get_line_count() - 2; class_desc->push_font(doc_code_font); + + if (constants[i].value.begins_with("Color(") && constants[i].value.ends_with(")")) { + String stripped = constants[i].value.replace(" ", "").replace("Color(", "").replace(")", ""); + Vector<float> color = stripped.split_floats(","); + if (color.size() >= 3) { + class_desc->push_color(Color(color[0], color[1], color[2])); + static const CharType prefix[3] = { 0x25CF /* filled circle */, ' ', 0 }; + class_desc->add_text(String(prefix)); + class_desc->pop(); + } + } + class_desc->push_color(headline_color); _add_text(constants[i].name); class_desc->pop(); @@ -1223,6 +1246,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { class_desc->push_color(value_color); _add_text(constants[i].value); class_desc->pop(); + class_desc->pop(); if (constants[i].description != "") { class_desc->push_font(doc_font); @@ -1440,8 +1464,6 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { } scroll_locked = false; - - return OK; } void EditorHelp::_request_help(const String &p_string) { @@ -1738,9 +1760,6 @@ void EditorHelp::_add_text(const String &p_bbcode) { _add_text_to_rt(p_bbcode, class_desc); } -void EditorHelp::_update_doc() { -} - void EditorHelp::generate_doc() { doc = memnew(DocData); @@ -1763,6 +1782,7 @@ void EditorHelp::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { class_desc->add_color_override("selection_color", get_color("text_editor/theme/selection_color", "Editor")); + _update_doc(); } break; diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 488980db07..99a2b2aa67 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -43,6 +43,9 @@ Size2 EditorProperty::get_minimum_size() const { Size2 ms; + Ref<Font> font = get_font("font", "Tree"); + ms.height = font->get_height(); + for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -70,12 +73,10 @@ Size2 EditorProperty::get_minimum_size() const { ms.width += check->get_width() + get_constant("hseparator", "Tree"); } - if (bottom_editor != NULL) { - Ref<Font> font = get_font("font", "Tree"); - ms.height += font->get_height(); + if (bottom_editor != NULL && bottom_editor->is_visible()) { ms.height += get_constant("vseparation", "Tree"); Size2 bems = bottom_editor->get_combined_minimum_size(); - bems.width += get_constant("item_margin", "Tree"); + //bems.width += get_constant("item_margin", "Tree"); ms.height += bems.height; ms.width = MAX(ms.width, bems.width); } @@ -98,6 +99,7 @@ void EditorProperty::_notification(int p_what) { int child_room = size.width * (1.0 - split_ratio); Ref<Font> font = get_font("font", "Tree"); int height = font->get_height(); + bool no_children = true; //compute room needed for (int i = 0; i < get_child_count(); i++) { @@ -113,11 +115,16 @@ void EditorProperty::_notification(int p_what) { Size2 minsize = c->get_combined_minimum_size(); child_room = MAX(child_room, minsize.width); height = MAX(height, minsize.height); + no_children = false; } - text_size = MAX(0, size.width - child_room + 4 * EDSCALE); - - rect = Rect2(text_size, 0, size.width - text_size, height); + if (no_children) { + text_size = size.width; + rect = Rect2(size.width - 1, 0, 1, height); + } else { + text_size = MAX(0, size.width - (child_room + 4 * EDSCALE)); + rect = Rect2(size.width - child_room, 0, child_room, height); + } if (bottom_editor) { @@ -178,7 +185,7 @@ void EditorProperty::_notification(int p_what) { draw_style_box(sb, Rect2(Vector2(), size)); } - if (right_child_rect != Rect2()) { + if (draw_top_bg && right_child_rect != Rect2()) { draw_rect(right_child_rect, dark_color); } if (bottom_child_rect != Rect2()) { @@ -189,7 +196,7 @@ void EditorProperty::_notification(int p_what) { if (draw_red) { color = get_color("error_color", "Editor"); } else { - color = get_color("font_color", "Tree"); + color = get_color("property_color", "Editor"); } if (label.find(".") != -1) { color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides @@ -787,6 +794,8 @@ void EditorProperty::_bind_methods() { EditorProperty::EditorProperty() { + draw_top_bg = true; + object = NULL; split_ratio = 0.5; selectable = true; text_size = 0; @@ -1613,32 +1622,10 @@ void EditorInspector::update_tree() { for (List<EditorInspectorPlugin::AddedEditor>::Element *F = editors.front(); F; F = F->next()) { EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor); - current_vbox->add_child(F->get().property_editor); if (ep) { - + //set all this before the control gets the ENTER_TREE notification ep->object = object; - ep->connect("property_changed", this, "_property_changed"); - if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) { - ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED); - } - ep->connect("property_keyed", this, "_property_keyed"); - ep->connect("property_keyed_with_value", this, "_property_keyed_with_value"); - ep->connect("property_checked", this, "_property_checked"); - ep->connect("selected", this, "_property_selected"); - ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); - ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); - ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); - if (doc_hint != String()) { - ep->set_tooltip(property_prefix + p.name + "::" + doc_hint); - } else { - ep->set_tooltip(property_prefix + p.name); - } - ep->set_draw_red(draw_red); - ep->set_use_folding(use_folding); - ep->set_checkable(checkable); - ep->set_checked(checked); - ep->set_keying(keying); if (F->get().properties.size()) { @@ -1664,8 +1651,35 @@ void EditorInspector::update_tree() { editor_property_map[prop].push_back(ep); } } + ep->set_draw_red(draw_red); + ep->set_use_folding(use_folding); + ep->set_checkable(checkable); + ep->set_checked(checked); + ep->set_keying(keying); ep->set_read_only(read_only); + } + + current_vbox->add_child(F->get().property_editor); + + if (ep) { + + ep->connect("property_changed", this, "_property_changed"); + if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) { + ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED); + } + ep->connect("property_keyed", this, "_property_keyed"); + ep->connect("property_keyed_with_value", this, "_property_keyed_with_value"); + ep->connect("property_checked", this, "_property_checked"); + ep->connect("selected", this, "_property_selected"); + ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); + ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); + ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); + if (doc_hint != String()) { + ep->set_tooltip(property_prefix + p.name + "::" + doc_hint); + } else { + ep->set_tooltip(property_prefix + p.name); + } ep->update_property(); ep->update_reload_status(); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 454622d662..ebe2124a40 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -68,6 +68,7 @@ private: bool can_revert; bool use_folding; + bool draw_top_bg; bool _might_be_in_instance(); bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage); @@ -149,6 +150,8 @@ public: String get_tooltip_text() const; + void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; } + EditorProperty(); }; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 158eedfb0f..b3ec717d85 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -54,7 +54,11 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f self->emit_signal("show_request"); */ - self->add_message(err_str, true); + if (p_type == ERR_HANDLER_WARNING) { + self->add_message(err_str, MSG_TYPE_WARNING); + } else { + self->add_message(err_str, MSG_TYPE_ERROR); + } } void EditorLog::_notification(int p_what) { @@ -95,22 +99,32 @@ void EditorLog::clear() { _clear_request(); } -void EditorLog::add_message(const String &p_msg, bool p_error) { +void EditorLog::add_message(const String &p_msg, MessageType p_type) { log->add_newline(); - if (p_error) { - log->push_color(get_color("error_color", "Editor")); - Ref<Texture> icon = get_icon("Error", "EditorIcons"); - log->add_image(icon); - log->add_text(" "); - tool_button->set_icon(icon); + bool restore = p_type != MSG_TYPE_STD; + switch (p_type) { + case MSG_TYPE_ERROR: { + log->push_color(get_color("error_color", "Editor")); + Ref<Texture> icon = get_icon("Error", "EditorIcons"); + log->add_image(icon); + log->add_text(" "); + tool_button->set_icon(icon); + } break; + case MSG_TYPE_WARNING: { + log->push_color(get_color("warning_color", "Editor")); + Ref<Texture> icon = get_icon("Warning", "EditorIcons"); + log->add_image(icon); + log->add_text(" "); + tool_button->set_icon(icon); + } break; } log->add_text(p_msg); //button->set_text(p_msg); - if (p_error) + if (restore) log->pop(); } diff --git a/editor/editor_log.h b/editor/editor_log.h index f9bc82de7d..8d0310d914 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -42,6 +42,7 @@ #include "scene/gui/panel_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tool_button.h" + class EditorLog : public VBoxContainer { GDCLASS(EditorLog, VBoxContainer); @@ -68,7 +69,13 @@ protected: void _notification(int p_what); public: - void add_message(const String &p_msg, bool p_error = false); + enum MessageType { + MSG_TYPE_STD, + MSG_TYPE_ERROR, + MSG_TYPE_WARNING + }; + + void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD); void set_tool_button(ToolButton *p_tool_button); void deinit(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index c942bacf9a..9272192318 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -63,6 +63,7 @@ #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_csv_translation.h" #include "editor/import/resource_importer_image.h" +#include "editor/import/resource_importer_layered_texture.h" #include "editor/import/resource_importer_obj.h" #include "editor/import/resource_importer_scene.h" #include "editor/import/resource_importer_texture.h" @@ -109,6 +110,7 @@ #include "editor/plugins/shader_graph_editor_plugin.h" #include "editor/plugins/skeleton_2d_editor_plugin.h" #include "editor/plugins/skeleton_editor_plugin.h" +#include "editor/plugins/skeleton_ik_editor_plugin.h" #include "editor/plugins/spatial_editor_plugin.h" #include "editor/plugins/sprite_editor_plugin.h" #include "editor/plugins/sprite_frames_editor_plugin.h" @@ -599,7 +601,7 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS); if (err != OK) { - show_accept(TTR("Error saving resource!"), TTR("I see...")); + show_accept(TTR("Error saving resource!"), TTR("OK")); return; } @@ -689,15 +691,15 @@ void EditorNode::_dialog_display_save_error(String p_file, Error p_error) { case ERR_FILE_CANT_WRITE: { - show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("I see...")); + show_accept(TTR("Can't open file for writing:") + " " + p_file.get_extension(), TTR("OK")); } break; case ERR_FILE_UNRECOGNIZED: { - show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("I see...")); + show_accept(TTR("Requested file format unknown:") + " " + p_file.get_extension(), TTR("OK")); } break; default: { - show_accept(TTR("Error while saving."), TTR("I see...")); + show_accept(TTR("Error while saving."), TTR("OK")); } break; } } @@ -711,23 +713,23 @@ void EditorNode::_dialog_display_load_error(String p_file, Error p_error) { case ERR_CANT_OPEN: { - show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Can't open '%s'. The file could have been moved or deleted."), p_file.get_file()), TTR("OK")); } break; case ERR_PARSE_ERROR: { - show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Error while parsing '%s'."), p_file.get_file()), TTR("OK")); } break; case ERR_FILE_CORRUPT: { - show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Unexpected end of file '%s'."), p_file.get_file()), TTR("OK")); } break; case ERR_FILE_NOT_FOUND: { - show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Missing '%s' or its dependencies."), p_file.get_file()), TTR("OK")); } break; default: { - show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("I see...")); + show_accept(vformat(TTR("Error while loading '%s'."), p_file.get_file()), TTR("OK")); } break; } } @@ -989,7 +991,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (!scene) { - show_accept(TTR("This operation can't be done without a tree root."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a tree root."), TTR("OK")); return; } @@ -1017,7 +1019,7 @@ void EditorNode::_save_scene(String p_file, int idx) { if (err != OK) { - show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see...")); + show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK")); return; } @@ -1025,7 +1027,7 @@ void EditorNode::_save_scene(String p_file, int idx) { // (hacky but needed for the tree to update properly) Node *dummy_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!dummy_scene) { - show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("I see...")); + show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK")); return; } memdelete(dummy_scene); @@ -1187,7 +1189,7 @@ void EditorNode::_dialog_action(String p_file) { ml = ResourceLoader::load(p_file, "MeshLibrary"); if (ml.is_null()) { - show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("I see...")); + show_accept(TTR("Can't load MeshLibrary for merging!"), TTR("OK")); return; } } @@ -1200,7 +1202,7 @@ void EditorNode::_dialog_action(String p_file) { Error err = ResourceSaver::save(p_file, ml); if (err) { - show_accept(TTR("Error saving MeshLibrary!"), TTR("I see...")); + show_accept(TTR("Error saving MeshLibrary!"), TTR("OK")); return; } @@ -1212,7 +1214,7 @@ void EditorNode::_dialog_action(String p_file) { tileset = ResourceLoader::load(p_file, "TileSet"); if (tileset.is_null()) { - show_accept(TTR("Can't load TileSet for merging!"), TTR("I see...")); + show_accept(TTR("Can't load TileSet for merging!"), TTR("OK")); return; } @@ -1225,7 +1227,7 @@ void EditorNode::_dialog_action(String p_file) { Error err = ResourceSaver::save(p_file, tileset); if (err) { - show_accept("Error saving TileSet!", "I see..."); + show_accept(TTR("Error saving TileSet!"), TTR("OK")); return; } } break; @@ -1579,7 +1581,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { Node *scene = editor_data.get_edited_scene_root(); if (!scene) { - show_accept(TTR("There is no defined scene to run."), TTR("I see...")); + show_accept(TTR("There is no defined scene to run."), TTR("OK")); return; } @@ -1633,7 +1635,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { if (scene->get_filename() == "") { - show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("I see...")); + show_accept(TTR("Current scene was never saved, please save it prior to running."), TTR("OK")); return; } @@ -1664,7 +1666,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { if (error != OK) { - show_accept(TTR("Could not start subprocess!"), TTR("I see...")); + show_accept(TTR("Could not start subprocess!"), TTR("OK")); return; } @@ -1787,7 +1789,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!scene) { - show_accept(TTR("This operation can't be done without a tree root."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a tree root."), TTR("OK")); break; } @@ -1850,7 +1852,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a scene."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a scene."), TTR("OK")); break; } @@ -1870,7 +1872,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { //Make sure that the scene has a root before trying to convert to tileset if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a root node."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a root node."), TTR("OK")); break; } @@ -1891,7 +1893,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { if (!editor_data.get_edited_scene_root()) { - show_accept(TTR("This operation can't be done without a selected node."), TTR("I see...")); + show_accept(TTR("This operation can't be done without a selected node."), TTR("OK")); break; } @@ -2168,7 +2170,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { OS::get_singleton()->set_low_processor_usage_mode(false); EditorSettings::get_singleton()->set_project_metadata("editor_options", "update_always", true); - show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("I see...")); + show_accept(TTR("This option is deprecated. Situations where refresh must be forced are now considered a bug. Please report."), TTR("OK")); } break; case SETTINGS_UPDATE_CHANGES: { @@ -2782,7 +2784,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b if (!lpath.begins_with("res://")) { - show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("Ugh")); + show_accept(TTR("Error loading scene, it must be inside the project path. Use 'Import' to open the scene, then save it inside the project path."), TTR("OK")); opening_prev = false; return ERR_FILE_NOT_FOUND; } @@ -4564,7 +4566,7 @@ static Node *_resource_get_edited_scene() { void EditorNode::_print_handler(void *p_this, const String &p_string, bool p_error) { EditorNode *en = (EditorNode *)p_this; - en->log->add_message(p_string, p_error); + en->log->add_message(p_string, p_error ? EditorLog::MSG_TYPE_ERROR : EditorLog::MSG_TYPE_STD); } EditorNode::EditorNode() { @@ -4665,6 +4667,16 @@ EditorNode::EditorNode() { import_texture.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_texture); + Ref<ResourceImporterLayeredTexture> import_3d; + import_3d.instance(); + import_3d->set_3d(true); + ResourceFormatImporter::get_singleton()->add_importer(import_3d); + + Ref<ResourceImporterLayeredTexture> import_array; + import_array.instance(); + import_array->set_3d(false); + ResourceFormatImporter::get_singleton()->add_importer(import_array); + Ref<ResourceImporterImage> import_image; import_image.instance(); ResourceFormatImporter::get_singleton()->add_importer(import_image); @@ -4761,8 +4773,10 @@ EditorNode::EditorNode() { EDITOR_DEF_RST("interface/scene_tabs/show_thumbnail_on_hover", true); EDITOR_DEF_RST("interface/inspector/capitalize_properties", true); EDITOR_DEF_RST("interface/inspector/disable_folding", false); + EDITOR_DEF("interface/inspector/horizontal_vector2_editing", false); + EDITOR_DEF("interface/inspector/horizontal_vector3_editing", true); EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); - EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial"); + EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial,Script"); EDITOR_DEF("run/auto_save/save_before_running", true); theme_base = memnew(Control); @@ -5434,6 +5448,7 @@ EditorNode::EditorNode() { bottom_panel->add_child(bottom_panel_vb); bottom_panel_hb = memnew(HBoxContainer); + bottom_panel_hb->set_custom_minimum_size(Size2(0, 24)); // Adjust for the height of the "Expand Bottom Dock" icon. bottom_panel_vb->add_child(bottom_panel_hb); bottom_panel_hb_editors = memnew(HBoxContainer); @@ -5596,6 +5611,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(SkeletonEditorPlugin(this))); + add_editor_plugin(memnew(SkeletonIKEditorPlugin(this))); add_editor_plugin(memnew(PhysicalBonePlugin(this))); // FIXME: Disabled as (according to reduz) users were complaining that it gets in the way diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 843267d673..a926401558 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -479,15 +479,6 @@ void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) { emit_signal("resource_saved", p_resource); } -Ref<SpatialEditorGizmo> EditorPlugin::create_spatial_gizmo(Spatial *p_spatial) { - //?? - if (get_script_instance() && get_script_instance()->has_method("create_spatial_gizmo")) { - return get_script_instance()->call("create_spatial_gizmo", p_spatial); - } - - return Ref<SpatialEditorGizmo>(); -} - bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { if (get_script_instance() && get_script_instance()->has_method("forward_canvas_gui_input")) { @@ -765,10 +756,6 @@ void EditorPlugin::_bind_methods() { ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - MethodInfo gizmo = MethodInfo(Variant::OBJECT, "create_spatial_gizmo", PropertyInfo(Variant::OBJECT, "for_spatial", PROPERTY_HINT_RESOURCE_TYPE, "Spatial")); - gizmo.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE; - gizmo.return_val.hint_string = "EditorSpatialGizmo"; - ClassDB::add_virtual_method(get_class_static(), gizmo); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::OBJECT, "get_plugin_icon")); ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen")); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 72e21b2f7f..c417f487dc 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -51,7 +51,6 @@ class Camera; class EditorSelection; class EditorExport; class EditorSettings; -class SpatialEditorGizmo; class EditorImportPlugin; class EditorExportPlugin; class EditorResourcePreview; @@ -171,7 +170,6 @@ public: void notify_scene_closed(const String &scene_filepath); void notify_resource_saved(const Ref<Resource> &p_resource); - virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event); virtual void forward_draw_over_viewport(Control *p_overlay); virtual void forward_force_draw_over_viewport(Control *p_overlay); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 79490f1c8e..59798bfab3 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -46,11 +46,22 @@ EditorPropertyNil::EditorPropertyNil() { } ///////////////////// TEXT ///////////////////////// + +void EditorPropertyText::_text_entered(const String &p_string) { + if (updating) + return; + + if (text->has_focus()) { + text->release_focus(); + _text_changed(p_string); + } +} + void EditorPropertyText::_text_changed(const String &p_string) { if (updating) return; - emit_signal("property_changed", get_edited_property(), p_string, true); + emit_signal("property_changed", get_edited_property(), p_string); } void EditorPropertyText::update_property() { @@ -64,6 +75,7 @@ void EditorPropertyText::update_property() { void EditorPropertyText::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed", "txt"), &EditorPropertyText::_text_changed); + ClassDB::bind_method(D_METHOD("_text_entered", "txt"), &EditorPropertyText::_text_entered); } EditorPropertyText::EditorPropertyText() { @@ -71,6 +83,8 @@ EditorPropertyText::EditorPropertyText() { add_child(text); add_focusable(text); text->connect("text_changed", this, "_text_changed"); + text->connect("text_entered", this, "_text_entered"); + updating = false; } @@ -78,12 +92,12 @@ EditorPropertyText::EditorPropertyText() { void EditorPropertyMultilineText::_big_text_changed() { text->set_text(big_text->get_text()); - emit_signal("property_changed", get_edited_property(), big_text->get_text(), true); + emit_signal("property_changed", get_edited_property(), big_text->get_text()); } void EditorPropertyMultilineText::_text_changed() { - emit_signal("property_changed", get_edited_property(), text->get_text(), true); + emit_signal("property_changed", get_edited_property(), text->get_text()); } void EditorPropertyMultilineText::_open_big_text() { @@ -1069,18 +1083,35 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo } EditorPropertyVector2::EditorPropertyVector2() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector2_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[2] = { "x", "y" }; for (int i = 0; i < 2; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_flat(true); spin[i]->set_label(desc[i]); - vb->add_child(spin[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } @@ -1195,19 +1226,35 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo } EditorPropertyVector3::EditorPropertyVector3() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[3] = { "x", "y", "z" }; for (int i = 0; i < 3; i++) { spin[i] = memnew(EditorSpinSlider); - spin[i]->set_label(desc[i]); spin[i]->set_flat(true); - - vb->add_child(spin[i]); + spin[i]->set_label(desc[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } ///////////////////// PLANE ///////////////////////// @@ -1259,18 +1306,36 @@ void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool } EditorPropertyPlane::EditorPropertyPlane() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[4] = { "x", "y", "z", "d" }; for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); - spin[i]->set_label(desc[i]); spin[i]->set_flat(true); - vb->add_child(spin[i]); + spin[i]->set_label(desc[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } @@ -1323,19 +1388,35 @@ void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p } EditorPropertyQuat::EditorPropertyQuat() { - VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); + bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector3_editing"); + + BoxContainer *bc; + + if (horizontal) { + bc = memnew(HBoxContainer); + add_child(bc); + set_bottom_editor(bc); + } else { + bc = memnew(VBoxContainer); + add_child(bc); + } + static const char *desc[4] = { "x", "y", "z", "w" }; for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); - spin[i]->set_label(desc[i]); spin[i]->set_flat(true); - - vb->add_child(spin[i]); + spin[i]->set_label(desc[i]); + bc->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); + if (horizontal) { + spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); + } + } + + if (!horizontal) { + set_label_reference(spin[0]); //show text and buttons around this } - set_label_reference(spin[0]); //show text and buttons around this setting = false; } @@ -2173,7 +2254,7 @@ void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) { void EditorPropertyResource::_open_editor_pressed() { RES res = get_edited_object()->get(get_edited_property()); if (res.is_valid()) { - EditorNode::get_singleton()->edit_resource(res.ptr()); + EditorNode::get_singleton()->edit_item(res.ptr()); } } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index ccd73d2539..d5fac9c1a0 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -54,6 +54,7 @@ class EditorPropertyText : public EditorProperty { bool updating; void _text_changed(const String &p_string); + void _text_entered(const String &p_string); protected: static void _bind_methods(); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 2bd28170e7..8203c85c6a 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -210,8 +210,8 @@ void EditorPropertyArray::update_property() { default: {} } - if (!array.is_array()) { - edit->set_text(arrtype + "[" + Variant::get_type_name(array.get_type()) + "]"); + if (array.get_type() == Variant::NIL) { + edit->set_text(String("(Nil) ") + arrtype); edit->set_pressed(false); if (vbox) { memdelete(vbox); @@ -219,7 +219,7 @@ void EditorPropertyArray::update_property() { return; } - edit->set_text(arrtype + "[" + itos(array.call("size")) + "]"); + edit->set_text(arrtype + "(size " + itos(array.call("size")) + ")"); #ifdef TOOLS_ENABLED @@ -613,7 +613,13 @@ void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) { void EditorPropertyDictionary::_add_key_value() { + // Do not allow nil as valid key. I experienced errors with this + if (object->get_new_item_key().get_type() == Variant::NIL) { + return; + } + Dictionary dict = object->get_dict(); + dict[object->get_new_item_key()] = object->get_new_item_value(); object->set_new_item_key(Variant()); object->set_new_item_value(Variant()); @@ -663,9 +669,20 @@ void EditorPropertyDictionary::_change_type_menu(int p_index) { void EditorPropertyDictionary::update_property() { - Dictionary dict = get_edited_object()->get(get_edited_property()); + Variant updated_val = get_edited_object()->get(get_edited_property()); + + if (updated_val.get_type() == Variant::NIL) { + edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property. + edit->set_pressed(false); + if (vbox) { + memdelete(vbox); + } + return; + } + + Dictionary dict = updated_val; - edit->set_text("Dict[" + itos(dict.size()) + "]"); + edit->set_text("Dictionary (size " + itos(dict.size()) + ")"); #ifdef TOOLS_ENABLED @@ -695,9 +712,9 @@ void EditorPropertyDictionary::update_property() { page->set_h_size_flags(SIZE_EXPAND_FILL); page->connect("value_changed", this, "_page_changed"); } else { - //bye bye children of the box - while (vbox->get_child_count() > 1) { - memdelete(vbox->get_child(1)); + // Queue childs for deletion, delete immediately might cause errors. + for (size_t i = 1; i < vbox->get_child_count(); i++) { + vbox->get_child(i)->queue_delete(); } } @@ -941,10 +958,10 @@ void EditorPropertyDictionary::update_property() { prop->update_property(); if (i == amount + 1) { - Button *add_item = memnew(Button); - add_item->set_text(TTR("Add Key/Value Pair")); - add_vbox->add_child(add_item); - add_item->connect("pressed", this, "_add_key_value"); + Button *butt_add_item = memnew(Button); + butt_add_item->set_text(TTR("Add Key/Value Pair")); + butt_add_item->connect("pressed", this, "_add_key_value"); + add_vbox->add_child(butt_add_item); } } @@ -965,8 +982,16 @@ void EditorPropertyDictionary::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { } } + void EditorPropertyDictionary::_edit_pressed() { + Variant prop_val = get_edited_object()->get(get_edited_property()); + if (prop_val.get_type() == Variant::NIL) { + Variant::CallError ce; + prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce); + get_edited_object()->set(get_edited_property(), prop_val); + } + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); update_property(); } diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index a04a7aab4f..d24816ee02 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -396,7 +396,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/cursor/block_caret", false); _initial_set("text_editor/cursor/caret_blink", true); - _initial_set("text_editor/cursor/caret_blink_speed", 0.65); + _initial_set("text_editor/cursor/caret_blink_speed", 0.5); hints["text_editor/cursor/caret_blink_speed"] = PropertyInfo(Variant::REAL, "text_editor/cursor/caret_blink_speed", PROPERTY_HINT_RANGE, "0.1, 10, 0.01"); _initial_set("text_editor/cursor/right_click_moves_caret", true); @@ -757,7 +757,7 @@ void EditorSettings::create() { } if (dir->change_dir(data_dir) != OK) { - dir->make_dir(data_dir); + dir->make_dir_recursive(data_dir); if (dir->change_dir(data_dir) != OK) { ERR_PRINT("Cannot create data directory!"); memdelete(dir); @@ -773,14 +773,8 @@ void EditorSettings::create() { // Validate/create cache dir - if (dir->change_dir(cache_path) != OK) { - ERR_PRINT("Cannot find path for cache directory!"); - memdelete(dir); - goto fail; - } - if (dir->change_dir(cache_dir) != OK) { - dir->make_dir(cache_dir); + dir->make_dir_recursive(cache_dir); if (dir->change_dir(cache_dir) != OK) { ERR_PRINT("Cannot create cache directory!"); memdelete(dir); @@ -790,14 +784,8 @@ void EditorSettings::create() { // Validate/create config dir and subdirectories - if (dir->change_dir(config_path) != OK) { - ERR_PRINT("Cannot find path for config directory!"); - memdelete(dir); - goto fail; - } - if (dir->change_dir(config_dir) != OK) { - dir->make_dir(config_dir); + dir->make_dir_recursive(config_dir); if (dir->change_dir(config_dir) != OK) { ERR_PRINT("Cannot create config directory!"); memdelete(dir); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 0e6d81d13b..b2c9f9865a 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -30,7 +30,13 @@ #include "editor_spin_slider.h" #include "editor_scale.h" +#include "math/expression.h" #include "os/input.h" + +String EditorSpinSlider::get_tooltip(const Point2 &p_pos) const { + return rtos(get_value()); +} + String EditorSpinSlider::get_text_value() const { int zeros = Math::step_decimals(get_step()); return String::num(get_value(), zeros); @@ -270,10 +276,12 @@ void EditorSpinSlider::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_ENTER) { /* Sorry, I dont like this, it makes navigating the different fields with arrows more difficult. * Just press enter to edit. - * if (!Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) { + * if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) { _focus_entered(); }*/ - + if ((Input::get_singleton()->is_action_pressed("ui_focus_next") || Input::get_singleton()->is_action_pressed("ui_focus_prev")) && !value_input_just_closed) { + _focus_entered(); + } value_input_just_closed = false; } } @@ -307,6 +315,21 @@ String EditorSpinSlider::get_label() const { return label; } +void EditorSpinSlider::_evaluate_input_text() { + String text = value_input->get_text(); + Ref<Expression> expr; + expr.instance(); + Error err = expr->parse(text); + if (err != OK) { + return; + } + + Variant v = expr->execute(Array(), NULL, false); + if (v.get_type() == Variant::NIL) + return; + set_value(v); +} + //text_entered signal void EditorSpinSlider::_value_input_entered(const String &p_text) { value_input_just_closed = true; @@ -315,13 +338,13 @@ void EditorSpinSlider::_value_input_entered(const String &p_text) { //modal_closed signal void EditorSpinSlider::_value_input_closed() { - set_value(value_input->get_text().to_double()); + _evaluate_input_text(); value_input_just_closed = true; } //focus_exited signal void EditorSpinSlider::_value_focus_exited() { - set_value(value_input->get_text().to_double()); + _evaluate_input_text(); // focus is not on the same element after the vlalue_input was exited // -> focus is on next element // -> TAB was pressed diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index fb32534ef4..e48eb171b8 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -73,6 +73,8 @@ class EditorSpinSlider : public Range { bool use_custom_label_color; Color custom_label_color; + void _evaluate_input_text(); + protected: void _notification(int p_what); void _gui_input(const Ref<InputEvent> &p_event); @@ -82,6 +84,8 @@ protected: void _focus_entered(); public: + String get_tooltip(const Point2 &p_pos) const; + String get_text_value() const; void set_label(const String &p_label); String get_label() const; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 18cc52a5c6..3995eb3dd6 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -175,7 +175,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = const Color warning_color = p_theme->get_color("warning_color", "Editor"); dark_icon_color_dictionary[Color::html("#ff5d5d")] = error_color; dark_icon_color_dictionary[Color::html("#45ff8b")] = success_color; - dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color; + dark_icon_color_dictionary[Color::html("#dbab09")] = warning_color; List<String> exceptions; exceptions.push_back("EditorPivot"); @@ -365,11 +365,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("mono_color", "Editor", mono_color); Color success_color = accent_color.linear_interpolate(Color(0.2, 1, 0.2), 0.6) * 1.2; - Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.2; + Color warning_color = accent_color.linear_interpolate(Color(1, 1, 0), 0.7) * 1.0; Color error_color = accent_color.linear_interpolate(Color(1, 0, 0), 0.8) * 1.7; + Color property_color = font_color.linear_interpolate(Color(0.5, 0.5, 0.5), 0.5); + if (!dark_theme) { // yellow on white themes is a P.I.T.A. - warning_color = accent_color.linear_interpolate(Color(1, 0.8, 0), 0.9); + warning_color = accent_color.linear_interpolate(Color(0.9, 0.7, 0), 0.9); warning_color = warning_color.linear_interpolate(mono_color, 0.2); success_color = success_color.linear_interpolate(mono_color, 0.2); error_color = error_color.linear_interpolate(mono_color, 0.2); @@ -377,6 +379,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("success_color", "Editor", success_color); theme->set_color("warning_color", "Editor", warning_color); theme->set_color("error_color", "Editor", error_color); + theme->set_color("property_color", "Editor", property_color); // 2d grid color const Color grid_minor_color = mono_color * Color(1.0, 1.0, 1.0, 0.07); @@ -825,6 +828,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_color", "LineEdit", font_color); theme->set_color("cursor_color", "LineEdit", font_color); theme->set_color("selection_color", "LineEdit", font_color_selection); + theme->set_color("clear_button_color", "LineEdit", font_color); + theme->set_color("clear_button_color_pressed", "LineEdit", accent_color); // TextEdit theme->set_stylebox("normal", "TextEdit", style_widget); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 931785333f..6c9d1568fa 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -178,7 +178,7 @@ void ExportTemplateManager::_uninstall_template_confirm() { _update_template_list(); } -void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { +bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { FileAccess *fa = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&fa); @@ -187,7 +187,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (!pkg) { EditorNode::get_singleton()->show_warning(TTR("Can't open export templates zip.")); - return; + return false; } int ret = unzGoToFirstFile(pkg); @@ -221,7 +221,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (data_str.get_slice_count(".") < 3) { EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside templates: %s."), data_str)); unzClose(pkg); - return; + return false; } version = data_str; @@ -237,7 +237,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (version == String()) { EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside templates.")); unzClose(pkg); - return; + return false; } String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); @@ -247,7 +247,7 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (err != OK) { EditorNode::get_singleton()->show_warning(TTR("Error creating path for templates:") + "\n" + template_path); unzClose(pkg); - return; + return false; } memdelete(d); @@ -310,6 +310,8 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ unzClose(pkg); _update_template_list(); + + return true; } void ExportTemplateManager::popup_manager() { @@ -401,7 +403,15 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int String path = download_templates->get_download_file(); template_list_state->set_text(TTR("Download Complete.")); template_downloader->hide(); - _install_from_file(path, false); + int ret = _install_from_file(path, false); + if (ret) { + Error err = OS::get_singleton()->move_to_trash(path); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + path + "\n"); + } + } else { + WARN_PRINTS(vformat(TTR("Templates installation failed. The problematic templates archives can be found at '%s'."), path)); + } } } break; } diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index 54a645c69f..bd43fe5dc5 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -70,7 +70,7 @@ class ExportTemplateManager : public ConfirmationDialog { void _uninstall_template_confirm(); virtual void ok_pressed(); - void _install_from_file(const String &p_file, bool p_use_progress = true); + bool _install_from_file(const String &p_file, bool p_use_progress = true); void _http_download_mirror_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); void _http_download_templates_completed(int p_status, int p_code, const PoolStringArray &headers, const PoolByteArray &p_data); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 61717927f5..ec1153a015 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -211,7 +211,8 @@ void FileSystemDock::_notification(int p_what) { files->connect("item_activated", this, "_select_file"); button_hist_next->connect("pressed", this, "_fw_history"); button_hist_prev->connect("pressed", this, "_bw_history"); - search_box->add_icon_override("right_icon", get_icon("Search", ei)); + search_box->set_right_icon(get_icon("Search", ei)); + search_box->set_clear_button_enabled(true); button_hist_next->set_icon(get_icon("Forward", ei)); button_hist_prev->set_icon(get_icon("Back", ei)); @@ -265,7 +266,8 @@ void FileSystemDock::_notification(int p_what) { button_hist_next->set_icon(get_icon("Forward", ei)); button_hist_prev->set_icon(get_icon("Back", ei)); - search_box->add_icon_override("right_icon", get_icon("Search", ei)); + search_box->set_right_icon(get_icon("Search", ei)); + search_box->set_clear_button_enabled(true); // Change size mode int new_file_list_mode = int(EditorSettings::get_singleton()->get("docks/filesystem/display_mode")); @@ -1429,7 +1431,7 @@ void FileSystemDock::_resource_created() const { RES current_res = RES(r); - editor->save_resource_as(current_res); + editor->save_resource_as(current_res, path); } void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { @@ -1451,7 +1453,7 @@ void FileSystemDock::_dir_rmb_pressed(const Vector2 &p_pos) { } folder_options->add_separator(); folder_options->add_item(TTR("New Folder..."), FOLDER_NEW_FOLDER); - folder_options->add_item(TTR("Show In File Manager"), FOLDER_SHOW_IN_EXPLORER); + folder_options->add_item(TTR("Open In File Manager"), FOLDER_SHOW_IN_EXPLORER); } folder_options->set_position(tree->get_global_position() + p_pos); folder_options->popup(); @@ -1760,7 +1762,10 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); - file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER); + + String fpath = files->get_item_metadata(p_item); + String item_text = fpath.ends_with("/") ? TTR("Open In File Manager") : TTR("Show In File Manager"); + file_options->add_item(item_text, FILE_SHOW_IN_EXPLORER); file_options->set_position(files->get_global_position() + p_pos); file_options->popup(); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 2bfd2eb5c3..0efd14e932 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -287,8 +287,10 @@ void GroupDialog::_notification(int p_what) { add_button->set_icon(get_icon("Forward", "EditorIcons")); remove_button->set_icon(get_icon("Back", "EditorIcons")); - add_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - remove_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + add_filter->set_right_icon(get_icon("Search", "EditorIcons")); + add_filter->set_clear_button_enabled(true); + remove_filter->set_right_icon(get_icon("Search", "EditorIcons")); + remove_filter->set_clear_button_enabled(true); } break; } } diff --git a/editor/icons/icon_add_atlas_tile.svg b/editor/icons/icon_add_atlas_tile.svg new file mode 100644 index 0000000000..912a0ce2c9 --- /dev/null +++ b/editor/icons/icon_add_atlas_tile.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#c9cfd4"/> +</svg> diff --git a/editor/icons/icon_add_autotile.svg b/editor/icons/icon_add_autotile.svg new file mode 100644 index 0000000000..2cc34d53b1 --- /dev/null +++ b/editor/icons/icon_add_autotile.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#4490fc"/> +</svg> diff --git a/editor/icons/icon_add_single_tile.svg b/editor/icons/icon_add_single_tile.svg new file mode 100644 index 0000000000..01af8e0649 --- /dev/null +++ b/editor/icons/icon_add_single_tile.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m7 1v6h-6v2h6v6h2v-6h6v-2h-6v-6h-2z" fill="#fce844"/> +</svg> diff --git a/editor/icons/icon_information_sign.svg b/editor/icons/icon_information_sign.svg new file mode 100644 index 0000000000..95002b6948 --- /dev/null +++ b/editor/icons/icon_information_sign.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg8" + sodipodi:docname="icon_information_sign.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata14"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs12" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1047" + inkscape:window-height="603" + id="namedview10" + showgrid="false" + inkscape:zoom="14.521571" + inkscape:cx="12.730205" + inkscape:cy="8.6526495" + inkscape:window-x="654" + inkscape:window-y="156" + inkscape:window-maximized="0" + inkscape:current-layer="svg8" /> + <path + style="fill:#ffb65d;fill-opacity:1;fill-rule:evenodd;stroke-width:0.57024062" + inkscape:connector-curvature="0" + id="path2" + d="m 4.5291945,14.892249 h 6.8428865 l 3.421444,-3.421444 V 4.6279186 L 11.372081,1.2064749 H 4.5291945 L 1.1077509,4.6279186 v 6.8428864 z" /> + <rect + style="fill:#ffffff;fill-opacity:1;stroke-width:0.57024062" + id="rect829" + width="2.6243541" + height="6.5062103" + x="6.6998501" + y="6.3477535" /> + <ellipse + style="fill:#ffffff;fill-opacity:1;stroke-width:0.57024062" + id="path831" + cx="8.0393629" + cy="4.2154655" + rx="1.3941878" + ry="1.3668507" /> +</svg> diff --git a/editor/icons/icon_texture_3_d.svg b/editor/icons/icon_texture_3_d.svg new file mode 100644 index 0000000000..dafdc8c68d --- /dev/null +++ b/editor/icons/icon_texture_3_d.svg @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_texture_3_d.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1853" + inkscape:window-height="1016" + id="namedview8" + showgrid="false" + inkscape:zoom="29.5" + inkscape:cx="15.226978" + inkscape:cy="9.4909723" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="1" + inkscape:current-layer="svg6" /> + <g + id="g830" + transform="translate(0.35954582,-0.28763666)"> + <path + d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z" + id="path2" + inkscape:connector-curvature="0" + style="fill:#e0e0e0;fill-opacity:0.99607999" + sodipodi:nodetypes="sssssssssccccc" /> + </g> + <g + aria-label="3D" + transform="scale(0.9167105,1.0908569)" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.12847996px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.20321201" + id="text834"> + <path + d="m 5.8175194,8.9717502 q -0.2194689,0 -0.4633233,-0.032514 Q 5.1103417,8.9148508 4.8827442,8.86608 4.6551468,8.8173091 4.4681918,8.7604097 4.2812367,8.7035104 4.1755665,8.6547395 L 4.4112924,7.646808 q 0.2113405,0.089413 0.5364797,0.1950835 0.3332677,0.097542 0.8209765,0.097542 0.5608651,0 0.8209764,-0.2113404 0.2601114,-0.2113405 0.2601114,-0.5689936 0,-0.219469 -0.097542,-0.3657816 Q 6.6628814,6.6388764 6.5003118,6.5494632 6.3377422,6.4519214 6.1101447,6.4194075 5.8906758,6.3787651 5.6386929,6.3787651 H 5.167241 V 5.4033475 h 0.5364797 q 0.1788266,0 0.3413962,-0.032514 0.1706981,-0.032514 0.3007537,-0.1056703 0.1300557,-0.081285 0.203212,-0.2113404 0.081285,-0.1381842 0.081285,-0.3413962 0,-0.1544411 -0.065028,-0.2682398 Q 6.5003118,4.3303881 6.3946415,4.2572318 6.2970998,4.1840755 6.1589156,4.1515616 6.0288599,4.1109192 5.8906758,4.1109192 q -0.3495247,0 -0.6502784,0.1056702 Q 4.9477721,4.3222597 4.7039177,4.4767008 L 4.2731082,3.5906965 Q 4.4031639,3.5094117 4.573862,3.4199984 4.7526886,3.3305851 4.964029,3.2574288 5.1753695,3.1842725 5.4110954,3.1355016 q 0.2438544,-0.048771 0.5120943,-0.048771 0.4958373,0 0.8534904,0.1219272 0.3657816,0.1137987 0.6015075,0.3332677 0.2357259,0.2113405 0.3495246,0.5039657 0.1137987,0.2844968 0.1137987,0.625893 0,0.3332677 -0.186955,0.6502784 -0.186955,0.3088822 -0.5039657,0.4714518 0.4389379,0.1788266 0.6746638,0.5364797 0.2438544,0.3495246 0.2438544,0.8453619 0,0.3901671 -0.1300557,0.7234347 Q 7.808997,8.22393 7.5326287,8.4677844 7.2562604,8.7035104 6.825451,8.8416945 6.40277,8.9717502 5.8175194,8.9717502 Z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201" + id="path836" /> + <path + d="m 10.502445,7.817506 q 0.08941,0.00813 0.203212,0.016257 0.121927,0 0.284497,0 0.951032,0 1.406227,-0.4795803 0.463323,-0.4795803 0.463323,-1.3249422 0,-0.8860044 -0.438938,-1.3411992 -0.438938,-0.4551949 -1.38997,-0.4551949 -0.130055,0 -0.26824,0.00813 -0.138184,0 -0.260111,0.016257 z M 14.16839,6.0292405 q 0,0.7315631 -0.227598,1.2761713 -0.227597,0.5446082 -0.650278,0.9022613 -0.414553,0.3576531 -1.01606,0.5364797 -0.601508,0.1788265 -1.349328,0.1788265 -0.341396,0 -0.796591,-0.032514 Q 9.6733402,8.86608 9.2344022,8.7766667 v -5.486724 q 0.438938,-0.081285 0.9103898,-0.1056702 0.47958,-0.032514 0.820976,-0.032514 0.723435,0 1.308686,0.1625696 0.593379,0.1625696 1.01606,0.5120943 0.422681,0.3495246 0.650278,0.8941328 0.227598,0.5446081 0.227598,1.3086853 z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.20321201" + id="path838" /> + </g> +</svg> diff --git a/editor/icons/icon_texture_array.svg b/editor/icons/icon_texture_array.svg new file mode 100644 index 0000000000..8297fc0f5d --- /dev/null +++ b/editor/icons/icon_texture_array.svg @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="16" + height="16" + version="1.1" + viewBox="0 0 16 16" + id="svg6" + sodipodi:docname="icon_texture_array.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1526" + inkscape:window-height="766" + id="namedview8" + showgrid="false" + inkscape:zoom="29.5" + inkscape:cx="8.3117238" + inkscape:cy="9.4909723" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg6" /> + <g + id="g830" + transform="translate(0.35954582,-0.28763666)"> + <path + d="M 2,1 C 1.4477153,1 1,1.4477153 1,2 v 12 c 0,0.552285 0.4477153,1 1,1 h 12 c 0.552285,0 1,-0.447715 1,-1 V 2 C 15,1.4477153 14.552285,1 14,1 Z m 1,2 h 10 v 8 H 3 Z" + id="path2" + inkscape:connector-curvature="0" + style="fill:#e0e0e0;fill-opacity:0.99607999" + sodipodi:nodetypes="sssssssssccccc" /> + </g> + <g + aria-label="[]" + transform="matrix(1.6197742,0,0,0.750929,-3.7231532,1.8329569)" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:8.29580784px;line-height:1.25;font-family:Ubuntu;-inkscape-font-specification:'Ubuntu Bold';letter-spacing:0px;word-spacing:0px;fill:#e0e0e0;fill-opacity:0.99607843;stroke:none;stroke-width:0.2073952" + id="text834"> + <path + d="M 4.7302951,2.4553483 H 6.978459 V 3.4425495 H 5.9082998 V 9.4984892 H 6.978459 V 10.48569 H 4.7302951 Z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952" + id="path862" + inkscape:connector-curvature="0" /> + <path + d="M 10.138643,10.48569 H 7.8904794 V 9.4984892 H 8.9606386 V 3.4425495 H 7.8904794 V 2.4553483 h 2.2481636 z" + style="fill:#e0e0e0;fill-opacity:0.99607843;stroke-width:0.2073952" + id="path864" + inkscape:connector-curvature="0" /> + </g> +</svg> diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index 7cfaa9070f..906d902b4a 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -203,7 +203,6 @@ Error EditorSceneImporterGLTF::_parse_nodes(GLTFState &state) { GLTFNode *node = memnew(GLTFNode); Dictionary n = nodes[i]; - print_line("node " + itos(i) + ": " + String(Variant(n))); if (n.has("name")) { node->name = n["name"]; } @@ -1657,6 +1656,7 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node if (n->mesh >= 0) { ERR_FAIL_INDEX(n->mesh, state.meshes.size()); MeshInstance *mi = memnew(MeshInstance); + print_line("**creating mesh for: " + n->name); GLTFMesh &mesh = state.meshes.write[n->mesh]; mi->set_mesh(mesh.mesh); if (mesh.mesh->get_name() == "") { @@ -1686,20 +1686,22 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node node->set_name(n->name); - p_parent->add_child(node); - node->set_owner(p_owner); - node->set_transform(n->xform); - n->godot_nodes.push_back(node); if (n->skin >= 0 && Object::cast_to<MeshInstance>(node)) { MeshInstance *mi = Object::cast_to<MeshInstance>(node); - //move skeleton around and place it on node, as the node _is_ a skeleton. + Skeleton *s = skeletons[n->skin]; - state.paths_to_skeleton[mi] = s; - //move it later, as skeleton may be moved around first + s->add_child(node); //According to spec, mesh should actually act as a child of the skeleton, as it inherits its transform + mi->set_skeleton_path(String("..")); + + } else { + p_parent->add_child(node); + node->set_transform(n->xform); } + node->set_owner(p_owner); + #if 0 for (int i = 0; i < n->skeleton_children.size(); i++) { @@ -1729,6 +1731,10 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto skeletons[i]->get_parent()->remove_child(skeletons[i]); p_parent_node->add_child(skeletons[i]); skeletons[i]->set_owner(owner); + //may have meshes as children, set owner in them too + for (int j = 0; j < skeletons[i]->get_child_count(); j++) { + skeletons[i]->get_child(j)->set_owner(owner); + } } } @@ -1744,10 +1750,8 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto const int parent = gltf_bone_node->parent; const int parent_index = s->find_bone(state.nodes[parent]->name); - s->add_bone(bone_name); const int bone_index = s->find_bone(bone_name); s->set_bone_parent(bone_index, parent_index); - s->set_bone_rest(bone_index, state.skins[skin].bones[n->joints[i].bone].inverse_bind.affine_inverse()); n->godot_nodes.push_back(s); n->joints.write[i].godot_bone_index = bone_index; @@ -1979,8 +1983,9 @@ void EditorSceneImporterGLTF::_import_animation(GLTFState &state, AnimationPlaye if (node->joints.size()) { Transform xform; - xform.basis = Basis(rot); - xform.basis.scale(scale); + //xform.basis = Basis(rot); + //xform.basis.scale(scale); + xform.basis.set_quat_scale(rot, scale); xform.origin = pos; Skeleton *skeleton = skeletons[node->joints[i].skin]; @@ -2061,6 +2066,10 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f if (name == "") { name = _gen_unique_name(state, "Skeleton"); } + for (int j = 0; j < state.skins[i].bones.size(); j++) { + s->add_bone(state.nodes[state.skins[i].bones[j].node]->name); + s->set_bone_rest(j, state.skins[i].bones[j].inverse_bind.affine_inverse()); + } s->set_name(name); root->add_child(s); s->set_owner(root); @@ -2074,12 +2083,6 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f } } - for (Map<Node *, Skeleton *>::Element *E = state.paths_to_skeleton.front(); E; E = E->next()) { - MeshInstance *mi = Object::cast_to<MeshInstance>(E->key()); - ERR_CONTINUE(!mi); - mi->set_skeleton_path(mi->get_path_to(E->get())); - } - for (int i = 0; i < skeletons.size(); i++) { skeletons[i]->localize_rests(); } diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index e8f3bdff62..8258ec41fd 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -275,7 +275,6 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Vector<GLTFAnimation> animations; Map<int, Vector<int> > skeleton_nodes; - Map<Node *, Skeleton *> paths_to_skeleton; //Map<int, Vector<int> > skin_users; //cache skin users diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp new file mode 100644 index 0000000000..2f958a6fdd --- /dev/null +++ b/editor/import/resource_importer_layered_texture.cpp @@ -0,0 +1,274 @@ +#include "resource_importer_layered_texture.h" + +#include "resource_importer_texture.h" + +#include "editor/editor_file_system.h" +#include "editor/editor_node.h" +#include "io/config_file.h" +#include "io/image_loader.h" +#include "scene/resources/texture.h" + +String ResourceImporterLayeredTexture::get_importer_name() const { + + return is_3d ? "texture_3d" : "texture_array"; +} + +String ResourceImporterLayeredTexture::get_visible_name() const { + + return is_3d ? "Texture3D" : "TextureArray"; +} +void ResourceImporterLayeredTexture::get_recognized_extensions(List<String> *p_extensions) const { + + ImageLoader::get_recognized_extensions(p_extensions); +} +String ResourceImporterLayeredTexture::get_save_extension() const { + return is_3d ? "tex3d" : "texarr"; +} + +String ResourceImporterLayeredTexture::get_resource_type() const { + + return is_3d ? "Texture3D" : "TextureArray"; +} + +bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { + + return true; +} + +int ResourceImporterLayeredTexture::get_preset_count() const { + return 3; +} +String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const { + + static const char *preset_names[] = { + "3D", + "2D", + "ColorCorrect" + }; + + return preset_names[p_idx]; +} + +void ResourceImporterLayeredTexture::get_import_options(List<ImportOption> *r_options, int p_preset) const { + + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Video RAM,Uncompressed", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirrored"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/filter"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "flags/mipmaps"), p_preset == PRESET_COLOR_CORRECT ? 0 : 1)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "flags/srgb", PROPERTY_HINT_ENUM, "Disable,Enable"), p_preset == PRESET_3D ? 1 : 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/horizontal", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 16 : 8)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slices/vertical", PROPERTY_HINT_RANGE, "1,256,1"), p_preset == PRESET_COLOR_CORRECT ? 1 : 8)); +} + +void ResourceImporterLayeredTexture::_save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags) { + + FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE); + f->store_8('G'); + f->store_8('D'); + if (is_3d) { + f->store_8('3'); + } else { + f->store_8('A'); + } + f->store_8('T'); //godot streamable texture + + f->store_32(p_images[0]->get_width()); + f->store_32(p_images[0]->get_height()); + f->store_32(p_images.size()); //depth + f->store_32(p_texture_flags); + if (p_compress_mode != COMPRESS_VIDEO_RAM) { + //vram needs to do a first compression to tell what the format is, for the rest its ok + f->store_32(p_images[0]->get_format()); + f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed + } + + if ((p_compress_mode == COMPRESS_LOSSLESS) && p_images[0]->get_format() > Image::FORMAT_RGBA8) { + p_compress_mode = COMPRESS_UNCOMPRESSED; //these can't go as lossy + } + + for (int i = 0; i < p_images.size(); i++) { + + switch (p_compress_mode) { + case COMPRESS_LOSSLESS: { + + Ref<Image> image = p_images[i]->duplicate(); + if (p_mipmaps) { + image->generate_mipmaps(); + } else { + image->clear_mipmaps(); + } + + int mmc = image->get_mipmap_count() + 1; + f->store_32(mmc); + + for (int i = 0; i < mmc; i++) { + + if (i > 0) { + image->shrink_x2(); + } + + PoolVector<uint8_t> data = Image::lossless_packer(image); + int data_len = data.size(); + f->store_32(data_len); + + PoolVector<uint8_t>::Read r = data.read(); + f->store_buffer(r.ptr(), data_len); + } + + } break; + case COMPRESS_VIDEO_RAM: { + + Ref<Image> image = p_images[i]->duplicate(); + image->generate_mipmaps(false); + + Image::CompressSource csource = Image::COMPRESS_SOURCE_LAYERED; + image->compress(p_vram_compression, csource, 0.7); + + if (i == 0) { + //hack so we can properly tell the format + f->store_32(image->get_format()); + f->store_32(p_compress_mode); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed + } + + PoolVector<uint8_t> data = image->get_data(); + int dl = data.size(); + + PoolVector<uint8_t>::Read r = data.read(); + f->store_buffer(r.ptr(), dl); + } break; + case COMPRESS_UNCOMPRESSED: { + + Ref<Image> image = p_images[i]->duplicate(); + + if (p_mipmaps) { + image->generate_mipmaps(); + } else { + image->clear_mipmaps(); + } + + PoolVector<uint8_t> data = image->get_data(); + int dl = data.size(); + + PoolVector<uint8_t>::Read r = data.read(); + + f->store_buffer(r.ptr(), dl); + + } break; + } + } + + memdelete(f); +} + +Error ResourceImporterLayeredTexture::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) { + + int compress_mode = p_options["compress/mode"]; + int repeat = p_options["flags/repeat"]; + bool filter = p_options["flags/filter"]; + bool mipmaps = p_options["flags/mipmaps"]; + int srgb = p_options["flags/srgb"]; + int hslices = p_options["slices/horizontal"]; + int vslices = p_options["slices/vertical"]; + + Ref<Image> image; + image.instance(); + Error err = ImageLoader::load_image(p_source_file, image, NULL, false, 1.0); + if (err != OK) + return err; + + int tex_flags = 0; + if (repeat > 0) + tex_flags |= Texture::FLAG_REPEAT; + if (repeat == 2) + tex_flags |= Texture::FLAG_MIRRORED_REPEAT; + if (filter) + tex_flags |= Texture::FLAG_FILTER; + if (mipmaps || compress_mode == COMPRESS_VIDEO_RAM) + tex_flags |= Texture::FLAG_MIPMAPS; + if (srgb == 1) + tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR; + + Vector<Ref<Image> > slices; + + int slice_w = image->get_width() / hslices; + int slice_h = image->get_height() / vslices; + + //optimize + if (compress_mode == COMPRESS_VIDEO_RAM) { + //if using video ram, optimize + if (srgb) { + //remove alpha if not needed, so compression is more efficient + if (image->get_format() == Image::FORMAT_RGBA8 && !image->detect_alpha()) { + image->convert(Image::FORMAT_RGB8); + } + } else { + image->optimize_channels(); + } + } + + for (int i = 0; i < vslices; i++) { + for (int j = 0; j < hslices; j++) { + int x = slice_w * j; + int y = slice_h * i; + Ref<Image> slice = image->get_rect(Rect2(x, y, slice_w, slice_h)); + ERR_CONTINUE(slice.is_null() || slice->empty()); + if (slice->get_width() != slice_w || slice->get_height() != slice_h) { + slice->resize(slice_w, slice_h); + } + slices.push_back(slice); + } + } + + String extension = get_save_extension(); + + if (compress_mode == COMPRESS_VIDEO_RAM) { + //must import in all formats, in order of priority (so platform choses the best supported one. IE, etc2 over etc). + //Android, GLES 2.x + + bool ok_on_pc = false; + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_s3tc")) { + + _save_tex(slices, p_save_path + ".s3tc." + extension, compress_mode, Image::COMPRESS_S3TC, mipmaps, tex_flags); + r_platform_variants->push_back("s3tc"); + ok_on_pc = true; + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc2")) { + + _save_tex(slices, p_save_path + ".etc2." + extension, compress_mode, Image::COMPRESS_ETC2, mipmaps, tex_flags); + r_platform_variants->push_back("etc2"); + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_etc")) { + _save_tex(slices, p_save_path + ".etc." + extension, compress_mode, Image::COMPRESS_ETC, mipmaps, tex_flags); + r_platform_variants->push_back("etc"); + } + + if (ProjectSettings::get_singleton()->get("rendering/vram_compression/import_pvrtc")) { + + _save_tex(slices, p_save_path + ".pvrtc." + extension, compress_mode, Image::COMPRESS_PVRTC4, mipmaps, tex_flags); + r_platform_variants->push_back("pvrtc"); + } + + if (!ok_on_pc) { + EditorNode::add_io_error("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correcly on PC."); + } + } else { + //import normally + _save_tex(slices, p_save_path + "." + extension, compress_mode, Image::COMPRESS_S3TC /*this is ignored */, mipmaps, tex_flags); + } + + return OK; +} + +ResourceImporterLayeredTexture *ResourceImporterLayeredTexture::singleton = NULL; + +ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() { + + singleton = this; + is_3d = true; +} + +ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() { +} diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h new file mode 100644 index 0000000000..ec73b2624d --- /dev/null +++ b/editor/import/resource_importer_layered_texture.h @@ -0,0 +1,57 @@ +#ifndef RESOURCE_IMPORTER_LAYERED_TEXTURE_H +#define RESOURCE_IMPORTER_LAYERED_TEXTURE_H + +#include "image.h" +#include "io/resource_import.h" + +class StreamTexture; + +class ResourceImporterLayeredTexture : public ResourceImporter { + GDCLASS(ResourceImporterLayeredTexture, ResourceImporter) + + bool is_3d; + +protected: + static void _texture_reimport_srgb(const Ref<StreamTexture> &p_tex); + static void _texture_reimport_3d(const Ref<StreamTexture> &p_tex); + static void _texture_reimport_normal(const Ref<StreamTexture> &p_tex); + + static ResourceImporterLayeredTexture *singleton; + +public: + static ResourceImporterLayeredTexture *get_singleton() { return singleton; } + virtual String get_importer_name() const; + virtual String get_visible_name() const; + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual String get_save_extension() const; + virtual String get_resource_type() const; + + enum Preset { + PRESET_3D, + PRESET_2D, + PRESET_COLOR_CORRECT, + }; + + enum CompressMode { + COMPRESS_LOSSLESS, + COMPRESS_VIDEO_RAM, + COMPRESS_UNCOMPRESSED + }; + + virtual int get_preset_count() const; + virtual String get_preset_name(int p_idx) const; + + virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const; + virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const; + + void _save_tex(const Vector<Ref<Image> > &p_images, const String &p_to_path, int p_compress_mode, Image::CompressMode p_vram_compression, bool p_mipmaps, int p_texture_flags); + + virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL); + + void update_imports(); + + void set_3d(bool p_3d) { is_3d = p_3d; } + ResourceImporterLayeredTexture(); + ~ResourceImporterLayeredTexture(); +}; +#endif // RESOURCE_IMPORTER_LAYERED_TEXTURE_H diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 43baabe2f5..615e9df043 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -142,7 +142,7 @@ void InspectorDock::_resource_file_selected(String p_file) { RES res = ResourceLoader::load(p_file); if (res.is_null()) { - warning_dialog->get_ok()->set_text("Ugh"); + warning_dialog->get_ok()->set_text(TTR("OK")); warning_dialog->set_text(TTR("Failed to load resource.")); return; }; @@ -529,7 +529,8 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { search = memnew(LineEdit); search->set_h_size_flags(Control::SIZE_EXPAND_FILL); search->set_placeholder(TTR("Filter properties")); - search->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search->set_right_icon(get_icon("Search", "EditorIcons")); + search->set_clear_button_enabled(true); add_child(search); warning = memnew(Button); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index e98dfceb90..4ed2b051aa 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -384,14 +384,11 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int return; } - progress->set_max(download->get_body_size()); - progress->set_value(download->get_downloaded_bytes()); - install->set_disabled(false); + status->set_text(TTR("Success!")); + // Make the progress bar invisible but don't reflow other Controls around it + progress->set_modulate(Color(0, 0, 0, 0)); - progress->set_value(download->get_downloaded_bytes()); - - status->set_text(TTR("Success!") + " (" + String::humanize_size(download->get_downloaded_bytes()) + ")"); set_process(false); } @@ -413,25 +410,37 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { - progress->set_max(download->get_body_size()); - progress->set_value(download->get_downloaded_bytes()); + // Make the progress bar visible again when retrying the download + progress->set_modulate(Color(1, 1, 1, 1)); + + if (download->get_downloaded_bytes() > 0) { + progress->set_max(download->get_body_size()); + progress->set_value(download->get_downloaded_bytes()); + } int cstatus = download->get_http_client_status(); - if (cstatus == HTTPClient::STATUS_BODY) - status->set_text(TTR("Fetching:") + " " + String::humanize_size(download->get_downloaded_bytes())); + if (cstatus == HTTPClient::STATUS_BODY) { + status->set_text(vformat(TTR("Downloading (%s / %s)..."), String::humanize_size(download->get_downloaded_bytes()), String::humanize_size(download->get_body_size()))); + } if (cstatus != prev_status) { switch (cstatus) { case HTTPClient::STATUS_RESOLVING: { status->set_text(TTR("Resolving...")); + progress->set_max(1); + progress->set_value(0); } break; case HTTPClient::STATUS_CONNECTING: { status->set_text(TTR("Connecting...")); + progress->set_max(1); + progress->set_value(0); } break; case HTTPClient::STATUS_REQUESTING: { status->set_text(TTR("Requesting...")); + progress->set_max(1); + progress->set_value(0); } break; default: {} } @@ -527,7 +536,7 @@ EditorAssetLibraryItemDownload::EditorAssetLibraryItemDownload() { hb2->add_child(retry); hb2->add_child(install); - set_custom_minimum_size(Size2(250, 0)); + set_custom_minimum_size(Size2(310, 0)); download = memnew(HTTPRequest); add_child(download); @@ -554,6 +563,8 @@ void EditorAssetLibrary::_notification(int p_what) { error_tr->set_texture(get_icon("Error", "EditorIcons")); reverse->set_icon(get_icon("Sort", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); error_label->raise(); } break; @@ -604,6 +615,8 @@ void EditorAssetLibrary::_notification(int p_what) { library_scroll_bg->add_style_override("panel", get_stylebox("bg", "Tree")); error_tr->set_texture(get_icon("Error", "EditorIcons")); reverse->set_icon(get_icon("Sort", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); } break; } } diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index eed6b5a95c..145a2ef9bb 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -375,33 +375,24 @@ Rect2 CanvasItemEditor::_get_encompassing_rect_from_list(List<CanvasItem *> p_li // Handles the first element CanvasItem *canvas_item = p_list.front()->get(); - Rect2 rect; - if (canvas_item->_edit_use_rect()) { - rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2()); - } else { - rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(Point2()), Size2()); - } + Rect2 rect = Rect2(canvas_item->get_global_transform_with_canvas().xform(canvas_item->_edit_get_rect().position + canvas_item->_edit_get_rect().size / 2), Size2()); // Expand with the other ones for (List<CanvasItem *>::Element *E = p_list.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); Transform2D xform = canvas_item->get_global_transform_with_canvas(); - if (canvas_item->_edit_use_rect()) { - Rect2 current_rect = canvas_item->_edit_get_rect(); - rect.expand_to(xform.xform(current_rect.position)); - rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0))); - rect.expand_to(xform.xform(current_rect.position + current_rect.size)); - rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y))); - } else { - rect.expand_to(xform.xform(Point2())); - } + Rect2 current_rect = canvas_item->_edit_get_rect(); + rect.expand_to(xform.xform(current_rect.position)); + rect.expand_to(xform.xform(current_rect.position + Vector2(current_rect.size.x, 0))); + rect.expand_to(xform.xform(current_rect.position + current_rect.size)); + rect.expand_to(xform.xform(current_rect.position + Vector2(0, current_rect.size.y))); } return rect; } -void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { +void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform, bool include_locked_nodes) { if (!p_node) return; if (Object::cast_to<Viewport>(p_node)) @@ -409,12 +400,6 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c const CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); - /*bool inherited = p_node != get_tree()->get_edited_scene_root() && p_node->get_filename() != ""; - bool editable = !inherited || EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(p_node); - bool lock_children = p_node->has_meta("_edit_group_") && p_node->get_meta("_edit_group_"); - - if (!lock_children && editable) {}*/ - for (int i = p_node->get_child_count() - 1; i >= 0; i--) { if (canvas_item && !canvas_item->is_set_as_toplevel()) { _expand_encompassing_rect_using_children(r_rect, p_node->get_child(i), r_first, p_parent_xform * canvas_item->get_transform(), p_canvas_xform); @@ -424,28 +409,17 @@ void CanvasItemEditor::_expand_encompassing_rect_using_children(Rect2 &r_rect, c } } - if (canvas_item && canvas_item->is_visible_in_tree() && !canvas_item->has_meta("_edit_lock_")) { + if (canvas_item && canvas_item->is_visible_in_tree() && (include_locked_nodes || !canvas_item->has_meta("_edit_lock_"))) { Transform2D xform = p_parent_xform * p_canvas_xform * canvas_item->get_transform(); - if (canvas_item->_edit_use_rect()) { - Rect2 rect = canvas_item->_edit_get_rect(); - if (r_first) { - r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2()); - r_first = false; - } - if (r_rect.size != Size2()) { - r_rect.expand_to(xform.xform(rect.position)); - r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0))); - r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y))); - r_rect.expand_to(xform.xform(rect.position + rect.size)); - } - } else { - if (r_first) { - r_rect = Rect2(xform.xform(Point2()), Size2()); - r_first = false; - } else { - r_rect.expand_to(xform.xform(Point2())); - } + Rect2 rect = canvas_item->_edit_get_rect(); + if (r_first) { + r_rect = Rect2(xform.xform(rect.position + rect.size / 2), Size2()); + r_first = false; } + r_rect.expand_to(xform.xform(rect.position)); + r_rect.expand_to(xform.xform(rect.position + Point2(rect.size.x, 0))); + r_rect.expand_to(xform.xform(rect.position + Point2(0, rect.size.y))); + r_rect.expand_to(xform.xform(rect.position + rect.size)); } } @@ -4879,7 +4853,7 @@ void CanvasItemEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str())); accept->popup_centered_minsize(); } diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index adc4010f39..2c943385ad 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -390,7 +390,7 @@ class CanvasItemEditor : public VBoxContainer { List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); - void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); + void _expand_encompassing_rect_using_children(Rect2 &p_rect, const Node *p_node, bool &r_first, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D(), bool include_locked_nodes = true); Rect2 _get_encompassing_rect(const Node *p_node); Object *_get_editor_data(Object *p_what); diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 1f5a4a8a36..7732103220 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -270,6 +270,12 @@ void ParticlesEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_GENERATE_AABB: { + float gen_time = node->get_lifetime(); + + if (gen_time < 1.0) + generate_seconds->set_value(1.0); + else + generate_seconds->set_value(trunc(gen_time) + 1.0); generate_aabb->popup_centered_minsize(); } break; case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_MESH: { @@ -323,7 +329,15 @@ void ParticlesEditor::_generate_aabb() { EditorProgress ep("gen_aabb", TTR("Generating AABB"), int(time)); + bool was_emitting = node->is_emitting(); + if (!was_emitting) { + node->set_emitting(true); + OS::get_singleton()->delay_usec(1000); + } + + running = 0.0; AABB rect; + while (running < time) { uint64_t ticks = OS::get_singleton()->get_ticks_usec(); @@ -339,6 +353,10 @@ void ParticlesEditor::_generate_aabb() { running += (OS::get_singleton()->get_ticks_usec() - ticks) / 1000000.0; } + if (!was_emitting) { + node->set_emitting(false); + } + node->set_visibility_aabb(rect); } diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 72a8b55a52..618c70d1a1 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -215,6 +215,10 @@ void PathSpatialGizmo::redraw() { clear(); + Ref<SpatialMaterial> path_material = gizmo_plugin->get_material("path_material"); + Ref<SpatialMaterial> path_thin_material = gizmo_plugin->get_material("path_thin_material"); + Ref<SpatialMaterial> handles_material = gizmo_plugin->get_material("handles"); + Ref<Curve3D> c = path->get_curve(); if (c.is_null()) return; @@ -238,7 +242,7 @@ void PathSpatialGizmo::redraw() { } if (v3p.size() > 1) { - add_lines(v3p, PathEditorPlugin::singleton->path_material); + add_lines(v3p, path_material); add_collision_segments(v3p); } @@ -265,13 +269,13 @@ void PathSpatialGizmo::redraw() { } if (v3p.size() > 1) { - add_lines(v3p, PathEditorPlugin::singleton->path_thin_material); + add_lines(v3p, path_thin_material); } if (handles.size()) { - add_handles(handles); + add_handles(handles, handles_material); } if (sec_handles.size()) { - add_handles(sec_handles, false, true); + add_handles(sec_handles, handles_material, false, true); } } } @@ -282,16 +286,6 @@ PathSpatialGizmo::PathSpatialGizmo(Path *p_path) { set_spatial_node(p_path); } -Ref<SpatialEditorGizmo> PathEditorPlugin::create_spatial_gizmo(Spatial *p_spatial) { - - if (Object::cast_to<Path>(p_spatial)) { - - return memnew(PathSpatialGizmo(Object::cast_to<Path>(p_spatial))); - } - - return Ref<SpatialEditorGizmo>(); -} - bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event) { if (!path) @@ -567,21 +561,9 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { mirror_handle_angle = true; mirror_handle_length = true; - path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - path_material->set_albedo(Color(0.5, 0.5, 1.0, 0.8)); - path_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - path_material->set_line_width(3); - path_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - path_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - - path_thin_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - path_thin_material->set_albedo(Color(0.5, 0.5, 1.0, 0.4)); - path_thin_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - path_thin_material->set_line_width(1); - path_thin_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - path_thin_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - - //SpatialEditor::get_singleton()->add_gizmo_plugin(this); + Ref<PathSpatialGizmoPlugin> gizmo_plugin; + gizmo_plugin.instance(); + SpatialEditor::get_singleton()->register_gizmo_plugin(gizmo_plugin); sep = memnew(VSeparator); sep->hide(); @@ -630,18 +612,53 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { curve_edit->set_pressed(true); /* - collision_polygon_editor = memnew( PathEditor(p_node) ); - editor->get_viewport()->add_child(collision_polygon_editor); + collision_polygon_editor = memnew( PathEditor(p_node) ); + editor->get_viewport()->add_child(collision_polygon_editor); + collision_polygon_editor->set_margin(MARGIN_LEFT,200); + collision_polygon_editor->set_margin(MARGIN_RIGHT,230); + collision_polygon_editor->set_margin(MARGIN_TOP,0); + collision_polygon_editor->set_margin(MARGIN_BOTTOM,10); + collision_polygon_editor->hide(); + */ +} - collision_polygon_editor->set_margin(MARGIN_LEFT,200); - collision_polygon_editor->set_margin(MARGIN_RIGHT,230); - collision_polygon_editor->set_margin(MARGIN_TOP,0); - collision_polygon_editor->set_margin(MARGIN_BOTTOM,10); +PathEditorPlugin::~PathEditorPlugin() { +} + +Ref<EditorSpatialGizmo> PathSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) { + Ref<PathSpatialGizmo> ref; + Path *path = Object::cast_to<Path>(p_spatial); + if (path) ref = Ref<PathSpatialGizmo>(memnew(PathSpatialGizmo(path))); - collision_polygon_editor->hide(); - */ + return ref; } -PathEditorPlugin::~PathEditorPlugin() { +String PathSpatialGizmoPlugin::get_name() const { + return "Path"; +} + +PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() { + + Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); + + Ref<SpatialMaterial> path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + path_color.a = 0.8; + path_material->set_albedo(path_color); + path_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + path_material->set_line_width(3); + path_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); + path_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + + Ref<SpatialMaterial> path_thin_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + path_color.a = 0.4; + path_thin_material->set_albedo(path_color); + path_thin_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + path_thin_material->set_line_width(1); + path_thin_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); + path_thin_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + + add_material("path_material", path_material); + add_material("path_thin_material", path_thin_material); + create_handle_material("handles"); } diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h index 52dfb78b61..61f309e794 100644 --- a/editor/plugins/path_editor_plugin.h +++ b/editor/plugins/path_editor_plugin.h @@ -49,10 +49,22 @@ public: virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - void redraw(); + virtual void redraw(); PathSpatialGizmo(Path *p_path = NULL); }; +class PathSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { + + GDCLASS(PathSpatialGizmoPlugin, EditorSpatialGizmoPlugin); + +protected: + Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial); + +public: + String get_name() const; + PathSpatialGizmoPlugin(); +}; + class PathEditorPlugin : public EditorPlugin { GDCLASS(PathEditorPlugin, EditorPlugin); @@ -88,12 +100,10 @@ public: Path *get_edited_path() { return path; } static PathEditorPlugin *singleton; - Ref<SpatialMaterial> path_material; - Ref<SpatialMaterial> path_thin_material; virtual bool forward_spatial_gui_input(Camera *p_camera, const Ref<InputEvent> &p_event); //virtual bool forward_gui_input(const InputEvent& p_event) { return collision_polygon_editor->forward_gui_input(p_event); } - virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); + //virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); virtual String get_name() const { return "Path"; } bool has_main_screen() const { return false; } virtual void edit(Object *p_object); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 6cc8f91e38..7d72537e32 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -219,6 +219,9 @@ void ScriptEditorQuickOpen::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { connect("confirmed", this, "_confirmed"); + + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } break; } } @@ -2894,7 +2897,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { script_list->set_v_size_flags(SIZE_EXPAND_FILL); script_split->set_split_offset(140); _sort_list_on_update = true; - script_list->connect("gui_input", this, "_script_list_gui_input"); + script_list->connect("gui_input", this, "_script_list_gui_input", varray(), CONNECT_DEFERRED); script_list->set_allow_rmb_select(true); script_list->set_drag_forwarding(this); @@ -3097,7 +3100,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { error_dialog = memnew(AcceptDialog); add_child(error_dialog); - error_dialog->get_ok()->set_text(TTR("I see...")); + error_dialog->get_ok()->set_text(TTR("OK")); debugger = memnew(ScriptEditorDebugger(editor)); debugger->connect("goto_script_line", this, "_goto_script_line"); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 0f48d42cf2..522ce52234 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -274,6 +274,23 @@ void ScriptTextEditor::_set_theme_for_script() { } } +void ScriptTextEditor::_toggle_warning_pannel(const Ref<InputEvent> &p_event) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + warnings_panel->set_visible(!warnings_panel->is_visible()); + } +} + +void ScriptTextEditor::_warning_clicked(Variant p_line) { + if (p_line.get_type() == Variant::INT) { + code_editor->get_text_edit()->cursor_set_line(p_line.operator int64_t()); + } else if (p_line.get_type() == Variant::DICTIONARY) { + Dictionary meta = p_line.operator Dictionary(); + code_editor->get_text_edit()->insert_at("#warning-ignore:" + meta["code"].operator String(), meta["line"].operator int64_t() - 1); + _validate_script(); + } +} + void ScriptTextEditor::reload_text() { ERR_FAIL_COND(script.is_null()); @@ -421,8 +438,9 @@ void ScriptTextEditor::_validate_script() { String text = te->get_text(); List<String> fnc; Set<int> safe_lines; + List<ScriptLanguage::Warning> warnings; - if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &safe_lines)) { + if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &warnings, &safe_lines)) { String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt; code_editor->set_error(error_text); } else { @@ -442,6 +460,37 @@ void ScriptTextEditor::_validate_script() { } } + code_editor->get_warning_count_label()->set_text(itos(warnings.size())); + warnings_panel->clear(); + warnings_panel->push_table(3); + for (List<ScriptLanguage::Warning>::Element *E = warnings.front(); E; E = E->next()) { + ScriptLanguage::Warning w = E->get(); + + warnings_panel->push_cell(); + warnings_panel->push_meta(w.line - 1); + warnings_panel->push_color(warnings_panel->get_color("warning_color", "Editor")); + warnings_panel->add_text(TTR("Line") + " " + itos(w.line)); + warnings_panel->add_text(" (" + w.string_code + "):"); + warnings_panel->pop(); // Color + warnings_panel->pop(); // Meta goto + warnings_panel->pop(); // Cell + + warnings_panel->push_cell(); + warnings_panel->add_text(w.message); + warnings_panel->pop(); // Cell + + Dictionary ignore_meta; + ignore_meta["line"] = w.line; + ignore_meta["code"] = w.string_code.to_lower(); + warnings_panel->push_cell(); + warnings_panel->push_meta(ignore_meta); + warnings_panel->add_text(TTR("(ignore)")); + warnings_panel->pop(); // Meta ignore + warnings_panel->pop(); // Cell + //warnings_panel->add_newline(); + } + warnings_panel->pop(); // Table + line--; bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true); bool last_is_safe = false; @@ -1022,6 +1071,8 @@ void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_goto_line", &ScriptTextEditor::_goto_line); ClassDB::bind_method("_lookup_symbol", &ScriptTextEditor::_lookup_symbol); ClassDB::bind_method("_text_edit_gui_input", &ScriptTextEditor::_text_edit_gui_input); + ClassDB::bind_method("_toggle_warning_pannel", &ScriptTextEditor::_toggle_warning_pannel); + ClassDB::bind_method("_warning_clicked", &ScriptTextEditor::_warning_clicked); ClassDB::bind_method("_color_changed", &ScriptTextEditor::_color_changed); ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); @@ -1333,8 +1384,13 @@ ScriptTextEditor::ScriptTextEditor() { theme_loaded = false; + VSplitContainer *editor_box = memnew(VSplitContainer); + add_child(editor_box); + editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE); + editor_box->set_v_size_flags(SIZE_EXPAND_FILL); + code_editor = memnew(CodeTextEditor); - add_child(code_editor); + editor_box->add_child(code_editor); code_editor->add_constant_override("separation", 0); code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); code_editor->connect("validate_script", this, "_validate_script"); @@ -1342,7 +1398,20 @@ ScriptTextEditor::ScriptTextEditor() { code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->get_text_edit()->connect("breakpoint_toggled", this, "_breakpoint_toggled"); code_editor->get_text_edit()->connect("symbol_lookup", this, "_lookup_symbol"); - code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + warnings_panel = memnew(RichTextLabel); + editor_box->add_child(warnings_panel); + warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); + warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); + warnings_panel->set_meta_underline(true); + warnings_panel->set_selection_enabled(true); + warnings_panel->set_focus_mode(FOCUS_CLICK); + warnings_panel->hide(); + + code_editor->get_warning_label()->connect("gui_input", this, "_toggle_warning_pannel"); + code_editor->get_warning_count_label()->connect("gui_input", this, "_toggle_warning_pannel"); + warnings_panel->connect("meta_clicked", this, "_warning_clicked"); update_settings(); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 334d410dbe..837201a947 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -39,6 +39,7 @@ class ScriptTextEditor : public ScriptEditorBase { GDCLASS(ScriptTextEditor, ScriptEditorBase); CodeTextEditor *code_editor; + RichTextLabel *warnings_panel; Ref<Script> script; @@ -124,6 +125,8 @@ protected: void _code_complete_script(const String &p_code, List<String> *r_options, bool &r_force); void _load_theme_settings(); void _set_theme_for_script(); + void _toggle_warning_pannel(const Ref<InputEvent> &p_event); + void _warning_clicked(Variant p_line); void _notification(int p_what); static void _bind_methods(); diff --git a/editor/plugins/skeleton_ik_editor_plugin.cpp b/editor/plugins/skeleton_ik_editor_plugin.cpp new file mode 100644 index 0000000000..2d343d3edd --- /dev/null +++ b/editor/plugins/skeleton_ik_editor_plugin.cpp @@ -0,0 +1,110 @@ +/*************************************************************************/ +/* skeleton_ik_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "skeleton_ik_editor_plugin.h" + +#include "scene/animation/skeleton_ik.h" + +void SkeletonIKEditorPlugin::_play() { + + if (!skeleton_ik) + return; + + if (!skeleton_ik->get_parent_skeleton()) + return; + + if (play_btn->is_pressed()) { + + initial_bone_poses.resize(skeleton_ik->get_parent_skeleton()->get_bone_count()); + for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { + initial_bone_poses.write[i] = skeleton_ik->get_parent_skeleton()->get_bone_pose(i); + } + + skeleton_ik->start(); + } else { + skeleton_ik->stop(); + + if (initial_bone_poses.size() != skeleton_ik->get_parent_skeleton()->get_bone_count()) + return; + + for (int i = 0; i < skeleton_ik->get_parent_skeleton()->get_bone_count(); ++i) { + skeleton_ik->get_parent_skeleton()->set_bone_pose(i, initial_bone_poses[i]); + } + } +} + +void SkeletonIKEditorPlugin::edit(Object *p_object) { + + if (p_object != skeleton_ik) { + if (skeleton_ik) { + play_btn->set_pressed(false); + _play(); + } + } + + SkeletonIK *s = Object::cast_to<SkeletonIK>(p_object); + if (!s) + return; + + skeleton_ik = s; +} + +bool SkeletonIKEditorPlugin::handles(Object *p_object) const { + + return p_object->is_class("SkeletonIK"); +} + +void SkeletonIKEditorPlugin::make_visible(bool p_visible) { + + if (p_visible) + play_btn->show(); + else + play_btn->hide(); +} + +void SkeletonIKEditorPlugin::_bind_methods() { + + ClassDB::bind_method("_play", &SkeletonIKEditorPlugin::_play); +} + +SkeletonIKEditorPlugin::SkeletonIKEditorPlugin(EditorNode *p_node) { + + editor = p_node; + play_btn = memnew(Button); + play_btn->set_icon(editor->get_gui_base()->get_icon("Play", "EditorIcons")); + play_btn->set_text(TTR("Play IK")); + play_btn->set_toggle_mode(true); + play_btn->hide(); + play_btn->connect("pressed", this, "_play"); + add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, play_btn); + skeleton_ik = NULL; +} + +SkeletonIKEditorPlugin::~SkeletonIKEditorPlugin() {} diff --git a/platform/haiku/power_haiku.h b/editor/plugins/skeleton_ik_editor_plugin.h index 2fe85cd23d..e645bea39a 100644 --- a/platform/haiku/power_haiku.h +++ b/editor/plugins/skeleton_ik_editor_plugin.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* power_haiku.h */ +/* skeleton_ik_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,26 +28,38 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PLATFORM_HAIKU_POWER_HAIKU_H_ -#define PLATFORM_HAIKU_POWER_HAIKU_H_ +#ifndef SKELETON_IK_EDITOR_PLUGIN_H +#define SKELETON_IK_EDITOR_PLUGIN_H -#include <os/os.h> +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" -class PowerHaiku { -private: - int nsecs_left; - int percent_left; - OS::PowerState power_state; +class SkeletonIK; - bool UpdatePowerInfo(); +class SkeletonIKEditorPlugin : public EditorPlugin { + + GDCLASS(SkeletonIKEditorPlugin, EditorPlugin); + + SkeletonIK *skeleton_ik; + + Button *play_btn; + EditorNode *editor; + Vector<Transform> initial_bone_poses; + + void _play(); + +protected: + static void _bind_methods(); public: - PowerHaiku(); - virtual ~PowerHaiku(); + virtual String get_name() const { return "SkeletonIK"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); - OS::PowerState get_power_state(); - int get_power_seconds_left(); - int get_power_percent_left(); + SkeletonIKEditorPlugin(EditorNode *p_node); + ~SkeletonIKEditorPlugin(); }; -#endif /* PLATFORM_HAIKU_POWER_HAIKU_H_ */ +#endif // SKELETON_IK_EDITOR_PLUGIN_H diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index eab1588a55..c3d48d498c 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -184,49 +184,6 @@ Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) con return camera_transform; } -String SpatialEditorGizmo::get_handle_name(int p_idx) const { - - if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) - return get_script_instance()->call("get_handle_name", p_idx); - - return ""; -} - -Variant SpatialEditorGizmo::get_handle_value(int p_idx) const { - - if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) - return get_script_instance()->call("get_handle_value", p_idx); - - return Variant(); -} - -void SpatialEditorGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - if (get_script_instance() && get_script_instance()->has_method("set_handle")) - get_script_instance()->call("set_handle", p_idx, p_camera, p_point); -} - -void SpatialEditorGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - if (get_script_instance() && get_script_instance()->has_method("commit_handle")) - get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel); -} - -bool SpatialEditorGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) { - - return false; -} - -bool SpatialEditorGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) { - - return false; -} - -SpatialEditorGizmo::SpatialEditorGizmo() { - - selected = false; -} - int SpatialEditorViewport::get_selected_count() const { Map<Node *, Object *> &selection = editor_selection->get_selection(); @@ -346,7 +303,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, Vector3 pos = _get_ray_pos(p_pos); Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<SpatialEditorGizmo> > found_gizmos; + Set<Ref<EditorSpatialGizmo> > found_gizmos; Node *edited_scene = get_tree()->get_edited_scene_root(); ObjectID closest = 0; @@ -361,7 +318,7 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, if (!spat) continue; - Ref<SpatialEditorGizmo> seg = spat->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spat->get_gizmo(); if ((!seg.is_valid()) || found_gizmos.has(seg)) { continue; @@ -418,7 +375,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl Vector3 pos = _get_ray_pos(p_pos); Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(pos, ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<SpatialEditorGizmo> > found_gizmos; + Set<Ref<EditorSpatialGizmo> > found_gizmos; r_includes_current = false; @@ -429,7 +386,7 @@ void SpatialEditorViewport::_find_items_at_pos(const Point2 &p_pos, bool &r_incl if (!spat) continue; - Ref<SpatialEditorGizmo> seg = spat->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spat->get_gizmo(); if (!seg.is_valid()) continue; @@ -559,7 +516,7 @@ void SpatialEditorViewport::_select_region() { if (selected.find(root_sp) != -1) continue; - Ref<SpatialEditorGizmo> seg = sp->get_gizmo(); + Ref<EditorSpatialGizmo> seg = sp->get_gizmo(); if (!seg.is_valid()) continue; @@ -963,7 +920,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (b->is_pressed() && _edit.gizmo.is_valid()) { //restore _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, true); - _edit.gizmo = Ref<SpatialEditorGizmo>(); + _edit.gizmo = Ref<EditorSpatialGizmo>(); } if (_edit.mode == TRANSFORM_NONE && b->is_pressed()) { @@ -1079,7 +1036,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (can_select_gizmos && spatial_editor->get_selected()) { - Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo(); if (seg.is_valid()) { int handle = -1; Vector3 point; @@ -1158,7 +1115,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { Spatial *spa = Object::cast_to<Spatial>(ObjectDB::get_instance(clicked)); if (spa) { - Ref<SpatialEditorGizmo> seg = spa->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spa->get_gizmo(); if (seg.is_valid()) { _edit.gizmo = seg; @@ -1175,7 +1132,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (_edit.gizmo.is_valid()) { _edit.gizmo->commit_handle(_edit.gizmo_handle, _edit.gizmo_initial_value, false); - _edit.gizmo = Ref<SpatialEditorGizmo>(); + _edit.gizmo = Ref<EditorSpatialGizmo>(); break; } if (clicked) { @@ -1233,7 +1190,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { if (spatial_editor->get_selected()) { - Ref<SpatialEditorGizmo> seg = spatial_editor->get_selected()->get_gizmo(); + Ref<EditorSpatialGizmo> seg = spatial_editor->get_selected()->get_gizmo(); if (seg.is_valid()) { int selected_handle = -1; @@ -2867,7 +2824,7 @@ void SpatialEditorViewport::update_transform_gizmo_view() { dd = 0.0001; float gsize = EditorSettings::get_singleton()->get("editors/3d/manipulator_gizmo_size"); - gizmo_scale = (gsize / Math::abs(dd)); + gizmo_scale = (gsize / Math::abs(dd)) * MAX(1, EDSCALE) / viewport_container->get_stretch_shrink(); Vector3 scale = Vector3(1, 1, 1) * gizmo_scale; xform.basis.scale(scale); @@ -3099,7 +3056,7 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const Vector3 world_pos = _get_ray_pos(p_pos); Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(world_pos, world_ray, get_tree()->get_root()->get_world()->get_scenario()); - Set<Ref<SpatialEditorGizmo> > found_gizmos; + Set<Ref<EditorSpatialGizmo> > found_gizmos; float closest_dist = MAX_DISTANCE; @@ -3113,7 +3070,7 @@ Vector3 SpatialEditorViewport::_get_instance_position(const Point2 &p_pos) const if (!mesh_instance) continue; - Ref<SpatialEditorGizmo> seg = mesh_instance->get_gizmo(); + Ref<EditorSpatialGizmo> seg = mesh_instance->get_gizmo(); if ((!seg.is_valid()) || found_gizmos.has(seg)) { continue; @@ -3308,7 +3265,7 @@ void SpatialEditorViewport::_perform_drop_data() { files_str += error_files[i].get_file().get_basename() + ","; } files_str = files_str.substr(0, files_str.length() - 1); - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), files_str.c_str())); accept->popup_centered_minsize(); } @@ -3389,7 +3346,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p if (root_node) { list.push_back(root_node); } else { - accept->get_ok()->set_text(TTR("OK :(")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); _remove_preview(); @@ -3397,7 +3354,7 @@ void SpatialEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p } } if (list.size() != 1) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); _remove_preview(); @@ -3429,6 +3386,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed clicked = 0; clicked_includes_current = false; orthogonal = false; + lock_rotation = false; message_time = 0; zoom_indicator_delay = 0.0; @@ -3892,10 +3850,6 @@ void SpatialEditor::select_gizmo_highlight_axis(int p_axis) { } } -int SpatialEditor::get_skeleton_visibility_state() const { - return view_menu->get_popup()->get_item_state(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON)); -} - void SpatialEditor::update_transform_gizmo() { List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -4048,6 +4002,16 @@ Dictionary SpatialEditor::get_state() const { d["znear"] = get_znear(); d["zfar"] = get_zfar(); + Dictionary gizmos_status; + for (int i = 0; i < gizmo_plugins.size(); i++) { + if (!gizmo_plugins[i]->can_be_hidden()) continue; + int state = gizmos_menu->get_item_state(gizmos_menu->get_item_index(i)); + String name = gizmo_plugins[i]->get_name(); + gizmos_status[name] = state; + } + + d["gizmos_status"] = gizmos_status; + return d; } void SpatialEditor::set_state(const Dictionary &p_state) { @@ -4121,6 +4085,39 @@ void SpatialEditor::set_state(const Dictionary &p_state) { VisualServer::get_singleton()->instance_set_visible(origin_instance, use); } } + + if (d.has("gizmos_status")) { + Dictionary gizmos_status = d["gizmos_status"]; + List<Variant> keys; + gizmos_status.get_key_list(&keys); + + for (int j = 0; j < gizmo_plugins.size(); ++j) { + if (!gizmo_plugins[j]->can_be_hidden()) continue; + int state = EditorSpatialGizmoPlugin::ON_TOP; + for (uint32_t i = 0; i < keys.size(); i++) { + if (gizmo_plugins.write[j]->get_name() == keys[i]) { + state = gizmos_status[keys[i]]; + } + } + + const int idx = gizmos_menu->get_item_index(j); + + gizmos_menu->set_item_multistate(idx, state); + gizmo_plugins.write[j]->set_state(state); + + switch (state) { + case EditorSpatialGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_visible")); + break; + case EditorSpatialGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_xray")); + break; + case EditorSpatialGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, gizmos_menu->get_icon("visibility_hidden")); + break; + } + } + } } void SpatialEditor::edit(Spatial *p_spatial) { @@ -4128,7 +4125,7 @@ void SpatialEditor::edit(Spatial *p_spatial) { if (p_spatial != selected) { if (selected) { - Ref<SpatialEditorGizmo> seg = selected->get_gizmo(); + Ref<EditorSpatialGizmo> seg = selected->get_gizmo(); if (seg.is_valid()) { seg->set_selected(false); selected->update_gizmo(); @@ -4140,7 +4137,7 @@ void SpatialEditor::edit(Spatial *p_spatial) { if (selected) { - Ref<SpatialEditorGizmo> seg = selected->get_gizmo(); + Ref<EditorSpatialGizmo> seg = selected->get_gizmo(); if (seg.is_valid()) { seg->set_selected(true); selected->update_gizmo(); @@ -4214,6 +4211,30 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) { } } +void SpatialEditor::_menu_gizmo_toggled(int p_option) { + + const int idx = gizmos_menu->get_item_index(p_option); + gizmos_menu->toggle_item_multistate(idx); + + // Change icon + const int state = gizmos_menu->get_item_state(idx); + switch (state) { + case EditorSpatialGizmoPlugin::ON_TOP: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); + break; + case EditorSpatialGizmoPlugin::VISIBLE: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); + break; + case EditorSpatialGizmoPlugin::HIDDEN: + gizmos_menu->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden")); + break; + } + + gizmo_plugins.write[p_option]->set_state(state); + + update_all_gizmos(); +} + void SpatialEditor::_menu_item_pressed(int p_option) { switch (p_option) { @@ -4388,28 +4409,6 @@ void SpatialEditor::_menu_item_pressed(int p_option) { _refresh_menu_icons(); } break; - case MENU_VISIBILITY_SKELETON: { - - const int idx = view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON); - view_menu->get_popup()->toggle_item_multistate(idx); - - // Change icon - const int state = view_menu->get_popup()->get_item_state(idx); - switch (state) { - case 0: - view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_hidden")); - break; - case 1: - view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_visible")); - break; - case 2: - view_menu->get_popup()->set_item_icon(idx, view_menu->get_popup()->get_icon("visibility_xray")); - break; - } - - update_all_gizmos(); - - } break; } } @@ -4519,9 +4518,9 @@ void SpatialEditor::_init_indicators() { nivec * 0.0 + ivec * (GIZMO_ARROW_OFFSET + GIZMO_ARROW_SIZE), }; - int arrow_sides = 6; + int arrow_sides = 16; - for (int k = 0; k < 6; k++) { + for (int k = 0; k < arrow_sides; k++) { Basis ma(ivec, Math_PI * 2 * float(k) / arrow_sides); Basis mb(ivec, Math_PI * 2 * float(k + 1) / arrow_sides); @@ -4605,10 +4604,10 @@ void SpatialEditor::_init_indicators() { ivec * 0.02 + ivec2 * 0.02 + ivec2 * GIZMO_CIRCLE_SIZE, }; - for (int k = 0; k < 32; k++) { + for (int k = 0; k < 64; k++) { - Basis ma(ivec, Math_PI * 2 * float(k) / 32); - Basis mb(ivec, Math_PI * 2 * float(k + 1) / 32); + Basis ma(ivec, Math_PI * 2 * float(k) / 64); + Basis mb(ivec, Math_PI * 2 * float(k + 1) / 64); for (int j = 0; j < 4; j++) { @@ -4725,6 +4724,26 @@ void SpatialEditor::_init_indicators() { _generate_selection_box(); } +struct _GizmoPluginComparator { + + bool operator()(const Ref<EditorSpatialGizmoPlugin> &p_a, const Ref<EditorSpatialGizmoPlugin> &p_b) const { + return p_a->get_name() < p_b->get_name(); + } +}; + +void SpatialEditor::_init_gizmos_menu() { + _register_all_gizmos(); + + gizmo_plugins.sort_custom<_GizmoPluginComparator>(); + + for (int i = 0; i < gizmo_plugins.size(); ++i) { + if (!gizmo_plugins[i]->can_be_hidden()) continue; + String plugin_name = gizmo_plugins[i]->get_name(); + gizmos_menu->add_multistate_item(TTR(plugin_name), 3, EditorSpatialGizmoPlugin::ON_TOP, i); + gizmos_menu->set_item_icon(gizmos_menu->get_item_index(i), gizmos_menu->get_icon("visibility_visible")); + } +} + void SpatialEditor::_init_grid() { PoolVector<Color> grid_colors[3]; @@ -5005,7 +5024,6 @@ void SpatialEditor::_notification(int p_what) { view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS), get_icon("Panels3", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_3_VIEWPORTS_ALT), get_icon("Panels3Alt", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_4_VIEWPORTS), get_icon("Panels4", "EditorIcons")); - view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VISIBILITY_SKELETON), view_menu->get_popup()->get_icon("visibility_visible")); _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT); @@ -5018,14 +5036,13 @@ void SpatialEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - gizmos = memnew(SpatialEditorGizmos); + _init_gizmos_menu(); _init_indicators(); } if (p_what == NOTIFICATION_EXIT_TREE) { _finish_indicators(); - memdelete(gizmos); } if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { tool_button[SpatialEditor::TOOL_MODE_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); @@ -5084,25 +5101,21 @@ void SpatialEditor::_request_gizmo(Object *p_obj) { return; if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) { - Ref<SpatialEditorGizmo> seg; + Ref<EditorSpatialGizmo> seg; - for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_editor_plugin_count(); i++) { + for (int i = 0; i < gizmo_plugins.size(); ++i) { + seg = gizmo_plugins.write[i]->get_gizmo(sp); - seg = EditorNode::get_singleton()->get_editor_data().get_editor_plugin(i)->create_spatial_gizmo(sp); - if (seg.is_valid()) - break; - } + if (seg.is_valid()) { + sp->set_gizmo(seg); - if (!seg.is_valid()) { - seg = gizmos->get_gizmo(sp); - } - if (seg.is_valid()) { - sp->set_gizmo(seg); - } + if (sp == selected) { + seg->set_selected(true); + selected->update_gizmo(); + } - if (seg.is_valid() && sp == selected) { - seg->set_selected(true); - selected->update_gizmo(); + break; + } } } } @@ -5158,11 +5171,35 @@ void SpatialEditor::_node_removed(Node *p_node) { selected = NULL; } +void SpatialEditor::_register_all_gizmos() { + register_gizmo_plugin(Ref<CameraSpatialGizmoPlugin>(memnew(CameraSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<LightSpatialGizmoPlugin>(memnew(LightSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<AudioStreamPlayer3DSpatialGizmoPlugin>(memnew(AudioStreamPlayer3DSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<MeshInstanceSpatialGizmoPlugin>(memnew(MeshInstanceSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<SoftBodySpatialGizmoPlugin>(memnew(SoftBodySpatialGizmoPlugin))); + register_gizmo_plugin(Ref<Sprite3DSpatialGizmoPlugin>(memnew(Sprite3DSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<Position3DSpatialGizmoPlugin>(memnew(Position3DSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<SkeletonSpatialGizmoPlugin>(memnew(SkeletonSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<RayCastSpatialGizmoPlugin>(memnew(RayCastSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<VehicleWheelSpatialGizmoPlugin>(memnew(VehicleWheelSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<VisibilityNotifierGizmoPlugin>(memnew(VisibilityNotifierGizmoPlugin))); + register_gizmo_plugin(Ref<ParticlesGizmoPlugin>(memnew(ParticlesGizmoPlugin))); + register_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); + register_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin))); + register_gizmo_plugin(Ref<BakedIndirectLightGizmoPlugin>(memnew(BakedIndirectLightGizmoPlugin))); + register_gizmo_plugin(Ref<CollisionShapeSpatialGizmoPlugin>(memnew(CollisionShapeSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<CollisionPolygonSpatialGizmoPlugin>(memnew(CollisionPolygonSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<NavigationMeshSpatialGizmoPlugin>(memnew(NavigationMeshSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<JointSpatialGizmoPlugin>(memnew(JointSpatialGizmoPlugin))); + register_gizmo_plugin(Ref<PhysicalBoneSpatialGizmoPlugin>(memnew(PhysicalBoneSpatialGizmoPlugin))); +} + void SpatialEditor::_bind_methods() { ClassDB::bind_method("_unhandled_key_input", &SpatialEditor::_unhandled_key_input); ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed); ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed); + ClassDB::bind_method("_menu_gizmo_toggled", &SpatialEditor::_menu_gizmo_toggled); ClassDB::bind_method("_menu_item_toggled", &SpatialEditor::_menu_item_toggled); ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action); ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data); @@ -5363,19 +5400,26 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_radio_check_shortcut(ED_SHORTCUT("spatial_editor/4_viewports", TTR("4 Viewports"), KEY_MASK_CMD + KEY_4), MENU_VIEW_USE_4_VIEWPORTS); p->add_separator(); + p->add_submenu_item(TTR("Gizmos"), "GizmosMenu"); + + p->add_separator(); + p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID); p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS); - p->add_separator(); - p->add_multistate_item(TTR("Skeleton Gizmo visibility"), 3, 1, MENU_VISIBILITY_SKELETON); - p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); p->connect("id_pressed", this, "_menu_item_pressed"); + gizmos_menu = memnew(PopupMenu); + p->add_child(gizmos_menu); + gizmos_menu->set_name("GizmosMenu"); + gizmos_menu->set_hide_on_checkable_item_selection(false); + gizmos_menu->connect("id_pressed", this, "_menu_gizmo_toggled"); + /* REST OF MENU */ palette_split = memnew(HSplitContainer); @@ -5583,6 +5627,10 @@ void SpatialEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) { spatial_editor->snap_cursor_to_plane(p_plane); } +void SpatialEditor::register_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> ref) { + gizmo_plugins.push_back(ref); +} + SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { editor = p_node; @@ -5596,3 +5644,182 @@ SpatialEditorPlugin::SpatialEditorPlugin(EditorNode *p_node) { SpatialEditorPlugin::~SpatialEditorPlugin() { } + +void EditorSpatialGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { + + Color instanced_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); + + Vector<Ref<SpatialMaterial> > mats; + + for (int i = 0; i < 4; i++) { + bool selected = i % 2 == 1; + bool instanced = i < 2; + + Ref<SpatialMaterial> material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + + Color color = instanced ? instanced_color : p_color; + + if (!selected) { + color.a *= 0.3; + } + + material->set_albedo(color); + material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + material->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN + 1); + + if (p_use_vertex_color) { + material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + } + + if (p_billboard) { + material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + } + + if (p_on_top && selected) { + material->set_on_top_of_alpha(); + } + + mats.push_back(material); + } + + materials[p_name] = mats; +} + +void EditorSpatialGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) { + + Color instanced_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); + + Vector<Ref<SpatialMaterial> > icons; + + for (int i = 0; i < 4; i++) { + bool selected = i % 2 == 1; + bool instanced = i < 2; + + Ref<SpatialMaterial> icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + + Color color = instanced ? instanced_color : p_albedo; + + if (!selected) { + color.a *= 0.3; + } + + icon->set_albedo(color); + + icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); + icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); + icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture); + icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); + icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + icon->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN); + + if (p_on_top && selected) { + icon->set_on_top_of_alpha(); + } + + icons.push_back(icon); + } + + materials[p_name] = icons; +} + +void EditorSpatialGizmoPlugin::create_handle_material(const String &p_name, bool p_billboard) { + Ref<SpatialMaterial> handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + + handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); + handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + handle_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true); + Ref<Texture> handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons"); + handle_material->set_point_size(handle_t->get_width()); + handle_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t); + handle_material->set_albedo(Color(1, 1, 1)); + handle_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + handle_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + handle_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + handle_material->set_on_top_of_alpha(); + if (p_billboard) { + handle_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); + handle_material->set_on_top_of_alpha(); + } + + materials[p_name] = Vector<Ref<SpatialMaterial> >(); + materials[p_name].push_back(handle_material); +} + +void EditorSpatialGizmoPlugin::add_material(const String &p_name, Ref<SpatialMaterial> p_material) { + materials[p_name] = Vector<Ref<SpatialMaterial> >(); + materials[p_name].push_back(p_material); +} + +Ref<SpatialMaterial> EditorSpatialGizmoPlugin::get_material(const String &p_name, EditorSpatialGizmo *p_gizmo) { + ERR_FAIL_COND_V(!materials.has(p_name), Ref<SpatialMaterial>()); + ERR_FAIL_COND_V(materials[p_name].size() == 0, Ref<SpatialMaterial>()); + + if (p_gizmo == NULL) return materials[p_name][0]; + + int index = (p_gizmo->is_selected() ? 1 : 0) + (p_gizmo->is_editable() ? 2 : 0); + + Ref<SpatialMaterial> mat = materials[p_name][index]; + + if (current_state == ON_TOP && p_gizmo->is_selected()) { + mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, true); + } else { + mat->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false); + } + + return mat; +} + +Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::get_gizmo(Spatial *p_spatial) { + + Ref<EditorSpatialGizmo> ref = create_gizmo(p_spatial); + + if (ref.is_null()) return ref; + + ref->set_plugin(this); + ref->set_spatial_node(p_spatial); + ref->set_hidden(current_state == HIDDEN); + + current_gizmos.push_back(ref.ptr()); + return ref; +} + +bool EditorSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return false; +} + +Ref<EditorSpatialGizmo> EditorSpatialGizmoPlugin::create_gizmo(Spatial *p_spatial) { + + Ref<EditorSpatialGizmo> ref; + if (has_gizmo(p_spatial)) ref.instance(); + return ref; +} + +bool EditorSpatialGizmoPlugin::can_be_hidden() const { + return true; +} + +bool EditorSpatialGizmoPlugin::is_selectable_when_hidden() const { + return false; +} + +void EditorSpatialGizmoPlugin::set_state(int p_state) { + current_state = p_state; + for (int i = 0; i < current_gizmos.size(); ++i) { + current_gizmos[i]->set_hidden(current_state == HIDDEN); + } +} + +void EditorSpatialGizmoPlugin::unregister_gizmo(EditorSpatialGizmo *p_gizmo) { + current_gizmos.erase(p_gizmo); +} + +EditorSpatialGizmoPlugin::EditorSpatialGizmoPlugin() { + current_state = ON_TOP; +} + +EditorSpatialGizmoPlugin::~EditorSpatialGizmoPlugin() { +} diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index bd449a28df..0ebc11e5df 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -43,11 +43,11 @@ class Camera; class SpatialEditor; -class SpatialEditorGizmos; +class EditorSpatialGizmoPlugin; -class SpatialEditorGizmo : public SpatialGizmo { +class EditorSpatialGizmo : public SpatialGizmo { - GDCLASS(SpatialEditorGizmo, SpatialGizmo); + GDCLASS(EditorSpatialGizmo, SpatialGizmo); bool selected; bool instanced; @@ -56,15 +56,86 @@ public: void set_selected(bool p_selected) { selected = p_selected; } bool is_selected() const { return selected; } + struct Instance { + + RID instance; + Ref<ArrayMesh> mesh; + RID skeleton; + bool billboard; + bool unscaled; + bool can_intersect; + bool extra_margin; + Instance() { + + billboard = false; + unscaled = false; + can_intersect = false; + extra_margin = false; + } + + void create_instance(Spatial *p_base, bool p_hidden = false); + }; + + Vector<Vector3> collision_segments; + Ref<TriangleMesh> collision_mesh; + + struct Handle { + Vector3 pos; + bool billboard; + }; + + Vector<Vector3> handles; + Vector<Vector3> secondary_handles; + float selectable_icon_size = -1.0f; + bool billboard_handle; + + bool valid; + bool hidden; + Spatial *base; + Vector<Instance> instances; + Spatial *spatial_node; + EditorSpatialGizmoPlugin *gizmo_plugin; + + void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); } + +protected: + static void _bind_methods(); + +public: + void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); + void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID()); + void add_collision_segments(const Vector<Vector3> &p_lines); + void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); + void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); + void add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard = false, bool p_secondary = false); + void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3()); + virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; + virtual Variant get_handle_value(int p_idx); virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - virtual bool is_gizmo_handle_highlighted(int idx) const { return false; } - virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); - virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); - SpatialEditorGizmo(); + void set_spatial_node(Spatial *p_node); + Spatial *get_spatial_node() const { return spatial_node; } + Vector3 get_handle_pos(int p_idx) const; + bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); + bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); + + virtual void clear(); + virtual void create(); + virtual void transform(); + virtual void redraw(); + virtual void free(); + + //TODO remove (?) + virtual bool is_editable() const; + virtual bool can_draw() const; + + void set_hidden(bool p_hidden); + void set_plugin(EditorSpatialGizmoPlugin *p_gizmo); + + EditorSpatialGizmo(); + ~EditorSpatialGizmo(); }; class SpatialEditorViewport : public Control { @@ -233,7 +304,7 @@ private: int edited_gizmo; Point2 mouse_pos; bool snap; - Ref<SpatialEditorGizmo> gizmo; + Ref<EditorSpatialGizmo> gizmo; int gizmo_handle; Variant gizmo_initial_value; Vector3 gizmo_initial_pos; @@ -489,10 +560,10 @@ private: MENU_VIEW_USE_4_VIEWPORTS, MENU_VIEW_ORIGIN, MENU_VIEW_GRID, + MENU_VIEW_GIZMOS_3D_ICONS, MENU_VIEW_CAMERA_SETTINGS, MENU_LOCK_SELECTED, MENU_UNLOCK_SELECTED, - MENU_VISIBILITY_SKELETON, MENU_SNAP_TO_FLOOR }; @@ -500,6 +571,7 @@ private: Button *tool_option_button[TOOL_OPT_MAX]; MenuButton *transform_menu; + PopupMenu *gizmos_menu; MenuButton *view_menu; ToolButton *lock_button; @@ -531,6 +603,7 @@ private: void _xform_dialog_action(); void _menu_item_pressed(int p_option); void _menu_item_toggled(bool pressed, int p_option); + void _menu_gizmo_toggled(int p_option); HBoxContainer *hbc_menu; @@ -539,6 +612,7 @@ private: void _instance_scene(); void _init_indicators(); + void _init_gizmos_menu(); void _init_grid(); void _finish_indicators(); void _finish_grid(); @@ -558,7 +632,10 @@ private: static SpatialEditor *singleton; void _node_removed(Node *p_node); - SpatialEditorGizmos *gizmos; + Vector<Ref<EditorSpatialGizmoPlugin> > gizmo_plugins; + + void _register_all_gizmos(); + SpatialEditor(); bool is_any_freelook_active() const; @@ -598,8 +675,6 @@ public: Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; } Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; } - int get_skeleton_visibility_state() const; - void update_transform_gizmo(); void update_all_gizmos(); void snap_selected_nodes_to_floor(); @@ -632,6 +707,8 @@ public: return viewports[p_idx]; } + void register_gizmo_plugin(Ref<EditorSpatialGizmoPlugin> ref); + Camera *get_camera() { return NULL; } void edit(Spatial *p_spatial); void clear(); @@ -668,4 +745,49 @@ public: ~SpatialEditorPlugin(); }; +class EditorSpatialGizmoPlugin : public Resource { + + GDCLASS(EditorSpatialGizmoPlugin, Resource); + +public: + static const int ON_TOP = 0; + static const int VISIBLE = 1; + static const int HIDDEN = 2; + +private: + int current_state; + List<EditorSpatialGizmo *> current_gizmos; + HashMap<String, Vector<Ref<SpatialMaterial> > > materials; + +protected: + virtual bool has_gizmo(Spatial *p_spatial); + virtual Ref<EditorSpatialGizmo> create_gizmo(Spatial *p_spatial); + +public: + void create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false); + void create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); + void create_handle_material(const String &p_name, bool p_billboard = false); + void add_material(const String &p_name, Ref<SpatialMaterial> p_material); + + Ref<SpatialMaterial> get_material(const String &p_name, EditorSpatialGizmo *p_gizmo = NULL); + + virtual String get_name() const = 0; + virtual bool can_be_hidden() const; + virtual bool is_selectable_when_hidden() const; + + virtual void redraw(EditorSpatialGizmo *p_gizmo) {} + virtual String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { return ""; } + virtual Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { return Variant(); } + virtual void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) {} + virtual void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) {} + virtual bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const { return false; } + + Ref<EditorSpatialGizmo> get_gizmo(Spatial *p_spatial); + void set_state(int p_state); + void unregister_gizmo(EditorSpatialGizmo *p_gizmo); + + EditorSpatialGizmoPlugin(); + virtual ~EditorSpatialGizmoPlugin(); +}; + #endif diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index e4fdd1f251..0419c3d4b1 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -57,8 +57,6 @@ void TextureRegionEditor::_region_draw() { base_tex = obj_styleBox->get_texture(); else if (atlas_tex.is_valid()) base_tex = atlas_tex->get_atlas(); - else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile)) - base_tex = tile_set->tile_get_texture(selected_tile); if (base_tex.is_null()) return; @@ -284,8 +282,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { r = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) r = atlas_tex->get_region(); - else if (tile_set.is_valid() && selected_tile != -1) - r = tile_set->tile_get_region(selected_tile); rect.expand_to(r.position); rect.expand_to(r.position + r.size); } @@ -302,9 +298,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (atlas_tex.is_valid()) { undo_redo->add_do_method(atlas_tex.ptr(), "set_region", rect); undo_redo->add_undo_method(atlas_tex.ptr(), "set_region", atlas_tex->get_region()); - } else if (tile_set.is_valid() && selected_tile != -1) { - undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, rect); - undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile)); } undo_redo->add_do_method(edit_draw, "update"); undo_redo->add_undo_method(edit_draw, "update"); @@ -327,8 +320,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { rect_prev = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect_prev = atlas_tex->get_region(); - else if (tile_set.is_valid() && selected_tile != -1) - rect_prev = tile_set->tile_get_region(selected_tile); for (int i = 0; i < 8; i++) { Vector2 tuv = endpoints[i]; @@ -372,9 +363,6 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { } else if (obj_styleBox.is_valid()) { undo_redo->add_do_method(obj_styleBox.ptr(), "set_region_rect", obj_styleBox->get_region_rect()); undo_redo->add_undo_method(obj_styleBox.ptr(), "set_region_rect", rect_prev); - } else if (tile_set.is_valid()) { - undo_redo->add_do_method(tile_set.ptr(), "tile_set_region", selected_tile, tile_set->tile_get_region(selected_tile)); - undo_redo->add_undo_method(tile_set.ptr(), "tile_set_region", selected_tile, rect_prev); } drag_index = -1; } @@ -595,8 +583,6 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { obj_styleBox->set_region_rect(rect); else if (atlas_tex.is_valid()) atlas_tex->set_region(rect); - else if (tile_set.is_valid() && selected_tile != -1) - tile_set->tile_set_region(selected_tile, rect); } void TextureRegionEditor::_notification(int p_what) { @@ -623,12 +609,11 @@ void TextureRegionEditor::_notification(int p_what) { } void TextureRegionEditor::_node_removed(Object *p_obj) { - if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr() || p_obj == tile_set.ptr()) { + if (p_obj == node_sprite || p_obj == node_ninepatch || p_obj == obj_styleBox.ptr() || p_obj == atlas_tex.ptr()) { node_ninepatch = NULL; node_sprite = NULL; obj_styleBox = Ref<StyleBox>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); - tile_set = Ref<TileSet>(NULL); hide(); } } @@ -677,8 +662,6 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox->remove_change_receptor(this); if (atlas_tex.is_valid()) atlas_tex->remove_change_receptor(this); - if (tile_set.is_valid()) - tile_set->remove_change_receptor(this); if (p_obj) { node_sprite = Object::cast_to<Sprite>(p_obj); node_ninepatch = Object::cast_to<NinePatchRect>(p_obj); @@ -686,8 +669,6 @@ void TextureRegionEditor::edit(Object *p_obj) { obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj)); if (Object::cast_to<AtlasTexture>(p_obj)) atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj)); - if (Object::cast_to<TileSet>(p_obj)) - tile_set = Ref<TileSet>(Object::cast_to<TileSet>(p_obj)); p_obj->add_change_receptor(this); _edit_region(); } else { @@ -695,7 +676,6 @@ void TextureRegionEditor::edit(Object *p_obj) { node_ninepatch = NULL; obj_styleBox = Ref<StyleBoxTexture>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); - tile_set = Ref<TileSet>(NULL); } edit_draw->update(); if (node_sprite && !node_sprite->is_region()) { @@ -724,8 +704,6 @@ void TextureRegionEditor::_edit_region() { texture = obj_styleBox->get_texture(); else if (atlas_tex.is_valid()) texture = atlas_tex->get_atlas(); - else if (tile_set.is_valid() && selected_tile != -1 && tile_set->has_tile(selected_tile)) - texture = tile_set->tile_get_texture(selected_tile); if (texture.is_null()) { edit_draw->update(); @@ -794,8 +772,6 @@ void TextureRegionEditor::_edit_region() { rect = obj_styleBox->get_region_rect(); else if (atlas_tex.is_valid()) rect = atlas_tex->get_region(); - else if (tile_set.is_valid() && selected_tile != -1) - rect = tile_set->tile_get_region(selected_tile); edit_draw->update(); } @@ -814,10 +790,8 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { node_ninepatch = NULL; obj_styleBox = Ref<StyleBoxTexture>(NULL); atlas_tex = Ref<AtlasTexture>(NULL); - tile_set = Ref<TileSet>(NULL); editor = p_editor; undo_redo = editor->get_undo_redo(); - selected_tile = -1; snap_step = Vector2(10, 10); snap_separation = Vector2(0, 0); diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index eeba1987a6..bd93be9267 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -38,7 +38,6 @@ #include "scene/gui/nine_patch_rect.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" -#include "scene/resources/tile_set.h" /** @author Mariano Suligoy @@ -56,8 +55,6 @@ class TextureRegionEditor : public Control { }; friend class TextureRegionEditorPlugin; - friend class TileSetEditor; - friend class TileSetEditorPlugin; MenuButton *snap_mode_button; TextureRect *icon_zoom; ToolButton *zoom_in; @@ -91,14 +88,12 @@ class TextureRegionEditor : public Control { Sprite *node_sprite; Ref<StyleBoxTexture> obj_styleBox; Ref<AtlasTexture> atlas_tex; - Ref<TileSet> tile_set; Rect2 rect; Rect2 rect_prev; float prev_margin; int edited_margin; List<Rect2> autoslice_cache; - int selected_tile; bool drag; bool creating; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 435ef229c5..101dc3037f 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -73,7 +73,8 @@ void TileMapEditor::_notification(int p_what) { rotate_180->set_icon(get_icon("Rotate180", "EditorIcons")); rotate_270->set_icon(get_icon("Rotate270", "EditorIcons")); - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); PopupMenu *p = options->get_popup(); p->set_item_icon(p->get_item_index(OPTION_PAINTING), get_icon("Edit", "EditorIcons")); @@ -168,10 +169,11 @@ void TileMapEditor::_menu_option(int p_option) { } void TileMapEditor::_palette_selected(int index) { + _update_palette(); +} - if (manual_autotile) { - _update_palette(); - } +void TileMapEditor::_palette_multi_selected(int index, bool selected) { + _update_palette(); } void TileMapEditor::_canvas_mouse_enter() { @@ -296,7 +298,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p } node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); - if (manual_autotile) { + if (manual_autotile || node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE) { if (current != -1) { node->set_cell_autotile_coord(p_pos.x, p_pos.y, position); } @@ -317,7 +319,6 @@ void TileMapEditor::_text_entered(const String &p_text) { } void TileMapEditor::_text_changed(const String &p_text) { - _update_palette(); } @@ -427,7 +428,7 @@ void TileMapEditor::_update_palette() { if (tex.is_valid()) { Rect2 region = tileset->tile_get_region(entries[i].id); - if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE) { + if (tileset->tile_get_tile_mode(entries[i].id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(entries[i].id) == TileSet::ATLAS_TILE) { int spacing = tileset->autotile_get_spacing(entries[i].id); region.size = tileset->autotile_get_size(entries[i].id); region.position += (region.size + Vector2(spacing, spacing)) * tileset->autotile_get_icon_coordinate(entries[i].id); @@ -450,7 +451,7 @@ void TileMapEditor::_update_palette() { palette->select(0); } - if (manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) { + if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) { const Map<Vector2, uint16_t> &tiles = tileset->autotile_get_bitmask_map(sel_tile); @@ -676,10 +677,10 @@ void TileMapEditor::_draw_cell(int p_cell, const Point2i &p_point, bool p_flip_h Vector2 tile_ofs = node->get_tileset()->tile_get_texture_offset(p_cell); Rect2 r = node->get_tileset()->tile_get_region(p_cell); - if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE) { + if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) { Vector2 offset; int selected = manual_palette->get_current(); - if (manual_autotile && selected != -1) { + if ((manual_autotile || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) && selected != -1) { offset = manual_palette->get_item_metadata(selected); } else { offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell); @@ -1673,6 +1674,7 @@ void TileMapEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_tileset_settings_changed"), &TileMapEditor::_tileset_settings_changed); ClassDB::bind_method(D_METHOD("_update_transform_buttons"), &TileMapEditor::_update_transform_buttons); ClassDB::bind_method(D_METHOD("_palette_selected"), &TileMapEditor::_palette_selected); + ClassDB::bind_method(D_METHOD("_palette_multi_selected"), &TileMapEditor::_palette_multi_selected); ClassDB::bind_method(D_METHOD("_fill_points"), &TileMapEditor::_fill_points); ClassDB::bind_method(D_METHOD("_erase_points"), &TileMapEditor::_erase_points); @@ -1800,6 +1802,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { palette->set_max_text_lines(2); palette->set_select_mode(ItemList::SELECT_MULTI); palette->connect("item_selected", this, "_palette_selected"); + palette->connect("multi_selected", this, "_palette_multi_selected"); palette_container->add_child(palette); // Add autotile override palette diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index b8443ca962..bb76879b02 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -184,6 +184,7 @@ class TileMapEditor : public VBoxContainer { void _update_palette(); void _menu_option(int p_option); void _palette_selected(int index); + void _palette_multi_selected(int index, bool selected); void _start_undo(const String &p_action); void _finish_undo(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 087c4293f1..8d1db5de8f 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "tile_set_editor_plugin.h" +#include "core/os/input.h" +#include "core/os/keyboard.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/physics_body_2d.h" #include "scene/2d/sprite.h" @@ -39,7 +41,9 @@ void TileSetEditor::edit(const Ref<TileSet> &p_tileset) { tileset = p_tileset; tileset->add_change_receptor(this); - update_tile_list(); + texture_list->clear(); + texture_map.clear(); + update_texture_list(); } void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { @@ -161,75 +165,6 @@ void TileSetEditor::_import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_ _import_node(p_scene, p_library); } -void TileSetEditor::_menu_confirm() { - - switch (option) { - - case MENU_OPTION_MERGE_FROM_SCENE: - case MENU_OPTION_CREATE_FROM_SCENE: { - - EditorNode *en = editor; - Node *scene = en->get_edited_scene(); - if (!scene) - break; - - _import_scene(scene, tileset, option == MENU_OPTION_MERGE_FROM_SCENE); - - } break; - } -} - -void TileSetEditor::_name_dialog_confirm(const String &name) { - - switch (option) { - - case MENU_OPTION_REMOVE_ITEM: { - - int id = tileset->find_tile_by_name(name); - - if (id < 0 && name.is_valid_integer()) - id = name.to_int(); - - if (tileset->has_tile(id)) { - tileset->remove_tile(id); - update_tile_list(); - } else { - err_dialog->set_text(TTR("Could not find tile:") + " " + name); - err_dialog->popup_centered(Size2(300, 60)); - } - } break; - } -} - -void TileSetEditor::_menu_cbk(int p_option) { - - option = p_option; - switch (p_option) { - - case MENU_OPTION_ADD_ITEM: { - tileset->create_tile(tileset->get_last_unused_tile_id()); - tileset->tile_set_name(tileset->get_last_unused_tile_id() - 1, itos(tileset->get_last_unused_tile_id() - 1)); - update_tile_list(); - } break; - case MENU_OPTION_REMOVE_ITEM: { - - nd->set_title(TTR("Remove Item")); - nd->set_text(TTR("Item name or ID:")); - nd->popup_centered(Size2(300, 95)); - } break; - case MENU_OPTION_CREATE_FROM_SCENE: { - - cd->set_text(TTR("Create from scene?")); - cd->popup_centered(Size2(300, 60)); - } break; - case MENU_OPTION_MERGE_FROM_SCENE: { - - cd->set_text(TTR("Merge from scene?")); - cd->popup_centered(Size2(300, 60)); - } break; - } -} - Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bool p_merge) { _import_scene(p_base_scene, ml, p_merge); @@ -237,28 +172,36 @@ Error TileSetEditor::update_library_file(Node *p_base_scene, Ref<TileSet> ml, bo } void TileSetEditor::_bind_methods() { - - ClassDB::bind_method("_menu_cbk", &TileSetEditor::_menu_cbk); - ClassDB::bind_method("_menu_confirm", &TileSetEditor::_menu_confirm); - ClassDB::bind_method("_name_dialog_confirm", &TileSetEditor::_name_dialog_confirm); - ClassDB::bind_method("_on_tile_list_selected", &TileSetEditor::_on_tile_list_selected); + ClassDB::bind_method("_on_tileset_toolbar_button_pressed", &TileSetEditor::_on_tileset_toolbar_button_pressed); + ClassDB::bind_method("_on_textures_added", &TileSetEditor::_on_textures_added); + ClassDB::bind_method("_on_tileset_toolbar_confirm", &TileSetEditor::_on_tileset_toolbar_confirm); + ClassDB::bind_method("_on_texture_list_selected", &TileSetEditor::_on_texture_list_selected); ClassDB::bind_method("_on_edit_mode_changed", &TileSetEditor::_on_edit_mode_changed); + ClassDB::bind_method("_on_workspace_mode_changed", &TileSetEditor::_on_workspace_mode_changed); ClassDB::bind_method("_on_workspace_overlay_draw", &TileSetEditor::_on_workspace_overlay_draw); + ClassDB::bind_method("_on_workspace_process", &TileSetEditor::_on_workspace_process); ClassDB::bind_method("_on_workspace_draw", &TileSetEditor::_on_workspace_draw); ClassDB::bind_method("_on_workspace_input", &TileSetEditor::_on_workspace_input); ClassDB::bind_method("_on_tool_clicked", &TileSetEditor::_on_tool_clicked); ClassDB::bind_method("_on_priority_changed", &TileSetEditor::_on_priority_changed); ClassDB::bind_method("_on_grid_snap_toggled", &TileSetEditor::_on_grid_snap_toggled); - ClassDB::bind_method("_set_snap_step_x", &TileSetEditor::_set_snap_step_x); - ClassDB::bind_method("_set_snap_step_y", &TileSetEditor::_set_snap_step_y); - ClassDB::bind_method("_set_snap_off_x", &TileSetEditor::_set_snap_off_x); - ClassDB::bind_method("_set_snap_off_y", &TileSetEditor::_set_snap_off_y); - ClassDB::bind_method("_set_snap_sep_x", &TileSetEditor::_set_snap_sep_x); - ClassDB::bind_method("_set_snap_sep_y", &TileSetEditor::_set_snap_sep_y); + ClassDB::bind_method("_set_snap_step", &TileSetEditor::_set_snap_step); + ClassDB::bind_method("_set_snap_off", &TileSetEditor::_set_snap_off); + ClassDB::bind_method("_set_snap_sep", &TileSetEditor::_set_snap_sep); } void TileSetEditor::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_icon(get_icon("ToolAddNode", "EditorIcons")); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_icon(get_icon("Remove", "EditorIcons")); + tileset_toolbar_tools->set_icon(get_icon("Tools", "EditorIcons")); + + tool_workspacemode[WORKSPACE_EDIT]->set_icon(get_icon("Edit", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_SINGLE]->set_icon(get_icon("AddSingleTile", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_AUTOTILE]->set_icon(get_icon("AddAutotile", "EditorIcons")); + tool_workspacemode[WORKSPACE_CREATE_ATLAS]->set_icon(get_icon("AddAtlasTile", "EditorIcons")); + tools[TOOL_SELECT]->set_icon(get_icon("ToolSelect", "EditorIcons")); tools[BITMASK_COPY]->set_icon(get_icon("Duplicate", "EditorIcons")); tools[BITMASK_PASTE]->set_icon(get_icon("Override", "EditorIcons")); @@ -266,91 +209,126 @@ void TileSetEditor::_notification(int p_what) { tools[SHAPE_NEW_POLYGON]->set_icon(get_icon("CollisionPolygon2D", "EditorIcons")); tools[SHAPE_DELETE]->set_icon(get_icon("Remove", "EditorIcons")); tools[SHAPE_KEEP_INSIDE_TILE]->set_icon(get_icon("Snap", "EditorIcons")); - tools[SHAPE_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); + tools[TOOL_GRID_SNAP]->set_icon(get_icon("SnapGrid", "EditorIcons")); tools[ZOOM_OUT]->set_icon(get_icon("ZoomLess", "EditorIcons")); tools[ZOOM_1]->set_icon(get_icon("ZoomReset", "EditorIcons")); tools[ZOOM_IN]->set_icon(get_icon("ZoomMore", "EditorIcons")); + tools[VISIBLE_INFO]->set_icon(get_icon("InformationSign", "EditorIcons")); + + tool_editmode[EDITMODE_REGION]->set_icon(get_icon("RegionEdit", "EditorIcons")); + tool_editmode[EDITMODE_COLLISION]->set_icon(get_icon("StaticBody2D", "EditorIcons")); + tool_editmode[EDITMODE_OCCLUSION]->set_icon(get_icon("LightOccluder2D", "EditorIcons")); + tool_editmode[EDITMODE_NAVIGATION]->set_icon(get_icon("Navigation2D", "EditorIcons")); + tool_editmode[EDITMODE_BITMASK]->set_icon(get_icon("PackedDataContainer", "EditorIcons")); + tool_editmode[EDITMODE_PRIORITY]->set_icon(get_icon("MaterialPreviewLight1", "EditorIcons")); + tool_editmode[EDITMODE_ICON]->set_icon(get_icon("LargeTexture", "EditorIcons")); } } -void TileSetEditor::_changed_callback(Object *p_changed, const char *p_prop) { - if (p_prop == StringName("region")) { - update_tile_list_icon(); - preview->set_region_rect(tileset->tile_get_region(get_current_tile())); - } else if (p_prop == StringName("name")) { - update_tile_list_icon(); - } else if (p_prop == StringName("texture") || p_prop == StringName("modulate") || p_prop == StringName("tile_mode")) { - _on_tile_list_selected(get_current_tile()); - workspace->update(); - preview->set_texture(tileset->tile_get_texture(get_current_tile())); - preview->set_modulate(tileset->tile_get_modulate(get_current_tile())); - preview->set_region_rect(tileset->tile_get_region(get_current_tile())); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) - property_editor->show(); - else - property_editor->hide(); - texture_region_editor->_edit_region(); - update_tile_list_icon(); - } else if (p_prop == StringName("autotile")) { - workspace->update(); - } -} +TileSetEditor::TileSetEditor(EditorNode *p_editor) { -void TileSetEditor::initialize_bottom_editor() { + editor = p_editor; + set_name("Tile Set Bottom Editor"); - //Side Panel - side_panel = memnew(Control); - side_panel->set_name("Tile Set"); + HSplitContainer *split = memnew(HSplitContainer); + split->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 10); + add_child(split); - VSplitContainer *split = memnew(VSplitContainer); - side_panel->add_child(split); - split->set_anchors_and_margins_preset(Control::PRESET_WIDE); + VBoxContainer *left_container = memnew(VBoxContainer); + split->add_child(left_container); - tile_list = memnew(ItemList); - tile_list->set_v_size_flags(SIZE_EXPAND_FILL); - tile_list->set_h_size_flags(SIZE_EXPAND_FILL); - tile_list->set_custom_minimum_size(Size2(10, 200)); - tile_list->connect("item_selected", this, "_on_tile_list_selected"); - split->add_child(tile_list); + texture_list = memnew(ItemList); + left_container->add_child(texture_list); + texture_list->set_v_size_flags(SIZE_EXPAND_FILL); + texture_list->set_custom_minimum_size(Size2(200, 0)); + texture_list->connect("item_selected", this, "_on_texture_list_selected"); - property_editor = memnew(PropertyEditor); - property_editor->set_v_size_flags(SIZE_EXPAND_FILL); - property_editor->set_h_size_flags(SIZE_EXPAND_FILL); - property_editor->set_custom_minimum_size(Size2(10, 70)); - split->add_child(property_editor); + HBoxContainer *tileset_toolbar_container = memnew(HBoxContainer); + left_container->add_child(tileset_toolbar_container); - helper = memnew(TileSetEditorHelper(this)); - property_editor->call_deferred("edit", helper); - helper->add_change_receptor(this); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE] = memnew(ToolButton); + Vector<Variant> p; + p.push_back((int)TOOL_TILESET_ADD_TEXTURE); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", p); + tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]); + tileset_toolbar_buttons[TOOL_TILESET_ADD_TEXTURE]->set_tooltip(TTR("Add Texture(s) to TileSet")); + + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE] = memnew(ToolButton); + p = Vector<Variant>(); + p.push_back((int)TOOL_TILESET_REMOVE_TEXTURE); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->connect("pressed", this, "_on_tileset_toolbar_button_pressed", p); + tileset_toolbar_container->add_child(tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]); + tileset_toolbar_buttons[TOOL_TILESET_REMOVE_TEXTURE]->set_tooltip(TTR("Remove current Texture from TileSet")); + + Control *toolbar_separator = memnew(Control); + toolbar_separator->set_h_size_flags(Control::SIZE_EXPAND_FILL); + tileset_toolbar_container->add_child(toolbar_separator); + + tileset_toolbar_tools = memnew(MenuButton); + tileset_toolbar_tools->set_text("Tools"); + p = Vector<Variant>(); + p.push_back((int)TOOL_TILESET_CREATE_SCENE); + tileset_toolbar_tools->get_popup()->add_item(TTR("Create from Scene"), TOOL_TILESET_CREATE_SCENE); + p = Vector<Variant>(); + p.push_back((int)TOOL_TILESET_MERGE_SCENE); + tileset_toolbar_tools->get_popup()->add_item(TTR("Merge from Scene"), TOOL_TILESET_MERGE_SCENE); - //Editor - //Bottom Panel - bottom_panel = memnew(Control); - bottom_panel->set_name("Tile Set Bottom Editor"); + tileset_toolbar_tools->get_popup()->connect("id_pressed", this, "_on_tileset_toolbar_button_pressed"); + tileset_toolbar_container->add_child(tileset_toolbar_tools); + + //--------------- + VBoxContainer *right_container = memnew(VBoxContainer); + right_container->set_v_size_flags(SIZE_EXPAND_FILL); + split->add_child(right_container); dragging_point = -1; creating_shape = false; snap_step = Vector2(32, 32); + snap_offset = WORKSPACE_MARGIN; - bottom_panel->set_custom_minimum_size(Size2(0, 150)); + set_custom_minimum_size(Size2(0, 150)); VBoxContainer *main_vb = memnew(VBoxContainer); - bottom_panel->add_child(main_vb); - main_vb->set_anchors_and_margins_preset(Control::PRESET_WIDE); + right_container->add_child(main_vb); + main_vb->set_v_size_flags(SIZE_EXPAND_FILL); HBoxContainer *tool_hb = memnew(HBoxContainer); Ref<ButtonGroup> g(memnew(ButtonGroup)); - String label[EDITMODE_MAX] = { "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" }; + String workspace_label[WORKSPACE_MODE_MAX] = { "Edit", "New Single Tile", "New Autotile", "New Atlas" }; + + for (int i = 0; i < (int)WORKSPACE_MODE_MAX; i++) { + tool_workspacemode[i] = memnew(Button); + tool_workspacemode[i]->set_text(workspace_label[i]); + tool_workspacemode[i]->set_toggle_mode(true); + tool_workspacemode[i]->set_button_group(g); + Vector<Variant> p; + p.push_back(i); + tool_workspacemode[i]->connect("pressed", this, "_on_workspace_mode_changed", p); + tool_hb->add_child(tool_workspacemode[i]); + } + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); + workspace_mode = WORKSPACE_EDIT; + + main_vb->add_child(tool_hb); + main_vb->add_child(memnew(HSeparator)); + + tool_hb = memnew(HBoxContainer); + Control *spacer = memnew(Control); + spacer->set_custom_minimum_size(Size2(30, 0)); + tool_hb->add_child(spacer); + + g = Ref<ButtonGroup>(memnew(ButtonGroup)); + String label[EDITMODE_MAX] = { "Region", "Collision", "Occlusion", "Navigation", "Bitmask", "Priority", "Icon" }; for (int i = 0; i < (int)EDITMODE_MAX; i++) { tool_editmode[i] = memnew(Button); tool_editmode[i]->set_text(label[i]); tool_editmode[i]->set_toggle_mode(true); tool_editmode[i]->set_button_group(g); - Vector<Variant> args; - args.push_back(i); - tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", args); + Vector<Variant> p; + p.push_back(i); + tool_editmode[i]->connect("pressed", this, "_on_edit_mode_changed", p); tool_hb->add_child(tool_editmode[i]); } tool_editmode[EDITMODE_COLLISION]->set_pressed(true); @@ -360,127 +338,52 @@ void TileSetEditor::initialize_bottom_editor() { main_vb->add_child(memnew(HSeparator)); toolbar = memnew(HBoxContainer); - for (int i = 0; i < (int)TOOLBAR_MAX; i++) { - tool_containers[i] = memnew(HBoxContainer); - toolbar->add_child(tool_containers[i]); - tool_containers[i]->hide(); - } - Ref<ButtonGroup> tg(memnew(ButtonGroup)); - Vector<Variant> p; + p = Vector<Variant>(); tools[TOOL_SELECT] = memnew(ToolButton); - tool_containers[TOOLBAR_DUMMY]->add_child(tools[TOOL_SELECT]); + toolbar->add_child(tools[TOOL_SELECT]); tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); tools[TOOL_SELECT]->set_toggle_mode(true); tools[TOOL_SELECT]->set_button_group(tg); tools[TOOL_SELECT]->set_pressed(true); p.push_back((int)TOOL_SELECT); tools[TOOL_SELECT]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_DUMMY]->show(); tools[BITMASK_COPY] = memnew(ToolButton); p.push_back((int)BITMASK_COPY); tools[BITMASK_COPY]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_COPY]); + toolbar->add_child(tools[BITMASK_COPY]); tools[BITMASK_PASTE] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)BITMASK_PASTE); tools[BITMASK_PASTE]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_PASTE]); + toolbar->add_child(tools[BITMASK_PASTE]); tools[BITMASK_CLEAR] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)BITMASK_CLEAR); tools[BITMASK_CLEAR]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_BITMASK]->add_child(tools[BITMASK_CLEAR]); + toolbar->add_child(tools[BITMASK_CLEAR]); tools[SHAPE_NEW_POLYGON] = memnew(ToolButton); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_NEW_POLYGON]); + toolbar->add_child(tools[SHAPE_NEW_POLYGON]); tools[SHAPE_NEW_POLYGON]->set_toggle_mode(true); tools[SHAPE_NEW_POLYGON]->set_button_group(tg); - tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator)); + toolbar->add_child(memnew(VSeparator)); tools[SHAPE_DELETE] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)SHAPE_DELETE); tools[SHAPE_DELETE]->connect("pressed", this, "_on_tool_clicked", p); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_DELETE]); - tool_containers[TOOLBAR_SHAPE]->add_child(memnew(VSeparator)); + toolbar->add_child(tools[SHAPE_DELETE]); + toolbar->add_child(memnew(VSeparator)); tools[SHAPE_KEEP_INSIDE_TILE] = memnew(ToolButton); tools[SHAPE_KEEP_INSIDE_TILE]->set_toggle_mode(true); tools[SHAPE_KEEP_INSIDE_TILE]->set_pressed(true); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); - tools[SHAPE_GRID_SNAP] = memnew(ToolButton); - tools[SHAPE_GRID_SNAP]->set_toggle_mode(true); - tools[SHAPE_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); - tool_containers[TOOLBAR_SHAPE]->add_child(tools[SHAPE_GRID_SNAP]); - - hb_grid = memnew(HBoxContainer); - tool_containers[TOOLBAR_SHAPE]->add_child(hb_grid); - - hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Offset:")))); - - sb_off_x = memnew(SpinBox); - sb_off_x->set_min(-256); - sb_off_x->set_max(256); - sb_off_x->set_step(1); - sb_off_x->set_value(snap_offset.x); - sb_off_x->set_suffix("px"); - sb_off_x->connect("value_changed", this, "_set_snap_off_x"); - hb_grid->add_child(sb_off_x); - - sb_off_y = memnew(SpinBox); - sb_off_y->set_min(-256); - sb_off_y->set_max(256); - sb_off_y->set_step(1); - sb_off_y->set_value(snap_offset.y); - sb_off_y->set_suffix("px"); - sb_off_y->connect("value_changed", this, "_set_snap_off_y"); - hb_grid->add_child(sb_off_y); - - hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Step:")))); - - sb_step_x = memnew(SpinBox); - sb_step_x->set_min(-256); - sb_step_x->set_max(256); - sb_step_x->set_step(1); - sb_step_x->set_value(snap_step.x); - sb_step_x->set_suffix("px"); - sb_step_x->connect("value_changed", this, "_set_snap_step_x"); - hb_grid->add_child(sb_step_x); - - sb_step_y = memnew(SpinBox); - sb_step_y->set_min(-256); - sb_step_y->set_max(256); - sb_step_y->set_step(1); - sb_step_y->set_value(snap_step.y); - sb_step_y->set_suffix("px"); - sb_step_y->connect("value_changed", this, "_set_snap_step_y"); - hb_grid->add_child(sb_step_y); - - hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Separation:")))); - - sb_sep_x = memnew(SpinBox); - sb_sep_x->set_min(0); - sb_sep_x->set_max(256); - sb_sep_x->set_step(1); - sb_sep_x->set_value(snap_separation.x); - sb_sep_x->set_suffix("px"); - sb_sep_x->connect("value_changed", this, "_set_snap_sep_x"); - hb_grid->add_child(sb_sep_x); - - sb_sep_y = memnew(SpinBox); - sb_sep_y->set_min(0); - sb_sep_y->set_max(256); - sb_sep_y->set_step(1); - sb_sep_y->set_value(snap_separation.y); - sb_sep_y->set_suffix("px"); - sb_sep_y->connect("value_changed", this, "_set_snap_sep_y"); - hb_grid->add_child(sb_sep_y); - - hb_grid->hide(); + toolbar->add_child(tools[SHAPE_KEEP_INSIDE_TILE]); + tools[TOOL_GRID_SNAP] = memnew(ToolButton); + tools[TOOL_GRID_SNAP]->set_toggle_mode(true); + tools[TOOL_GRID_SNAP]->connect("toggled", this, "_on_grid_snap_toggled"); + toolbar->add_child(tools[TOOL_GRID_SNAP]); spin_priority = memnew(SpinBox); spin_priority->set_min(1); @@ -491,8 +394,6 @@ void TileSetEditor::initialize_bottom_editor() { spin_priority->hide(); toolbar->add_child(spin_priority); - tool_containers[TOOLBAR_SHAPE]->show(); - Control *separator = memnew(Control); separator->set_h_size_flags(SIZE_EXPAND_FILL); toolbar->add_child(separator); @@ -502,22 +403,31 @@ void TileSetEditor::initialize_bottom_editor() { p.push_back((int)ZOOM_OUT); tools[ZOOM_OUT]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[ZOOM_OUT]); + tools[ZOOM_OUT]->set_tooltip(TTR("Zoom Out")); tools[ZOOM_1] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)ZOOM_1); tools[ZOOM_1]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[ZOOM_1]); + tools[ZOOM_1]->set_tooltip(TTR("Reset Zoom")); tools[ZOOM_IN] = memnew(ToolButton); p = Vector<Variant>(); p.push_back((int)ZOOM_IN); tools[ZOOM_IN]->connect("pressed", this, "_on_tool_clicked", p); toolbar->add_child(tools[ZOOM_IN]); + tools[ZOOM_IN]->set_tooltip(TTR("Zoom In")); + + tools[VISIBLE_INFO] = memnew(ToolButton); + tools[VISIBLE_INFO]->set_toggle_mode(true); + tools[VISIBLE_INFO]->set_tooltip(TTR("Display tile's names (hold Alt Key)")); + toolbar->add_child(tools[VISIBLE_INFO]); main_vb->add_child(toolbar); scroll = memnew(ScrollContainer); main_vb->add_child(scroll); scroll->set_v_size_flags(SIZE_EXPAND_FILL); + scroll->set_clip_contents(true); workspace_container = memnew(Control); scroll->add_child(workspace_container); @@ -527,6 +437,7 @@ void TileSetEditor::initialize_bottom_editor() { workspace_container->add_child(workspace_overlay); workspace = memnew(Control); + workspace->set_focus_mode(FOCUS_ALL); workspace->connect("draw", this, "_on_workspace_draw"); workspace->connect("gui_input", this, "_on_workspace_input"); workspace->set_draw_behind_parent(true); @@ -536,39 +447,35 @@ void TileSetEditor::initialize_bottom_editor() { workspace->add_child(preview); preview->set_centered(false); preview->set_draw_behind_parent(true); - preview->set_region(true); -} + preview->set_position(WORKSPACE_MARGIN); -TileSetEditor::TileSetEditor(EditorNode *p_editor) { - - menu = memnew(MenuButton); - CanvasItemEditor::get_singleton()->add_control_to_menu_panel(menu); - menu->hide(); - menu->set_text(TTR("Tile Set")); - menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM); - menu->get_popup()->add_item(TTR("Remove Item"), MENU_OPTION_REMOVE_ITEM); - menu->get_popup()->add_separator(); - menu->get_popup()->add_item(TTR("Create from Scene"), MENU_OPTION_CREATE_FROM_SCENE); - menu->get_popup()->add_item(TTR("Merge from Scene"), MENU_OPTION_MERGE_FROM_SCENE); - menu->get_popup()->connect("id_pressed", this, "_menu_cbk"); - editor = p_editor; + //--------------- cd = memnew(ConfirmationDialog); add_child(cd); - cd->get_ok()->connect("pressed", this, "_menu_confirm"); - - nd = memnew(EditorNameDialog); - add_child(nd); - nd->set_hide_on_ok(true); - nd->get_line_edit()->set_margin(MARGIN_TOP, 28); - nd->connect("name_confirmed", this, "_name_dialog_confirm"); + cd->connect("confirmed", this, "_on_tileset_toolbar_confirm"); + //--------------- err_dialog = memnew(AcceptDialog); add_child(err_dialog); - err_dialog->set_title(TTR("Error")); - draw_handles = false; + //--------------- + texture_dialog = memnew(EditorFileDialog); + texture_dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); + texture_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILES); + texture_dialog->clear_filters(); + List<String> extensions; + + ResourceLoader::get_recognized_extensions_for_type("Texture", &extensions); + for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - initialize_bottom_editor(); + texture_dialog->add_filter("*." + E->get() + " ; " + E->get().to_upper()); + } + add_child(texture_dialog); + texture_dialog->connect("files_selected", this, "_on_textures_added"); + + //--------------- + helper = memnew(TilesetEditorContext(this)); + tile_names_opacity = 0; } TileSetEditor::~TileSetEditor() { @@ -576,57 +483,166 @@ TileSetEditor::~TileSetEditor() { memdelete(helper); } -void TileSetEditor::_on_tile_list_selected(int p_index) { - if (get_current_tile() >= 0) { +void TileSetEditor::_on_tileset_toolbar_button_pressed(int p_index) { + option = p_index; + switch (option) { + case TOOL_TILESET_ADD_TEXTURE: { + texture_dialog->popup_centered_ratio(); + } break; + case TOOL_TILESET_REMOVE_TEXTURE: { + if (get_current_texture().is_valid()) { + cd->set_text(TTR("Remove Selected Textue and ALL TILES wich uses it?")); + cd->popup_centered(Size2(300, 60)); + } else { + err_dialog->set_text(TTR("You haven't selected a texture to remove.")); + err_dialog->popup_centered(Size2(300, 60)); + } + } break; + case TOOL_TILESET_CREATE_SCENE: { + + cd->set_text(TTR("Create from scene?")); + cd->popup_centered(Size2(300, 60)); + } break; + case TOOL_TILESET_MERGE_SCENE: { + + cd->set_text(TTR("Merge from scene?")); + cd->popup_centered(Size2(300, 60)); + } break; + } +} + +void TileSetEditor::_on_tileset_toolbar_confirm() { + switch (option) { + case TOOL_TILESET_REMOVE_TEXTURE: { + RID current_rid = get_current_texture()->get_rid(); + List<int> ids; + tileset->get_tile_list(&ids); + for (List<int>::Element *E = ids.front(); E; E = E->next()) { + if (tileset->tile_get_texture(E->get())->get_rid() == current_rid) { + tileset->remove_tile(E->get()); + } + } + texture_list->remove_item(texture_list->find_metadata(current_rid)); + texture_map.erase(current_rid); + _on_texture_list_selected(-1); + } break; + case TOOL_TILESET_MERGE_SCENE: + case TOOL_TILESET_CREATE_SCENE: { + + EditorNode *en = editor; + Node *scene = en->get_edited_scene(); + if (!scene) + break; + _import_scene(scene, tileset, option == TOOL_TILESET_MERGE_SCENE); + + edit(tileset); + } break; + } +} + +void TileSetEditor::_on_texture_list_selected(int p_index) { + if (get_current_texture().is_valid()) { current_item_index = p_index; - preview->set_texture(tileset->tile_get_texture(get_current_tile())); - preview->set_modulate(tileset->tile_get_modulate(get_current_tile())); - preview->set_region_rect(tileset->tile_get_region(get_current_tile())); - workspace->set_custom_minimum_size(tileset->tile_get_region(get_current_tile()).size); + preview->set_texture(get_current_texture()); + workspace->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); + workspace_container->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); + workspace_overlay->set_custom_minimum_size(get_current_texture()->get_size() + WORKSPACE_MARGIN * 2); update_workspace_tile_mode(); } else { current_item_index = -1; preview->set_texture(NULL); workspace->set_custom_minimum_size(Size2i()); + update_workspace_tile_mode(); } - texture_region_editor->selected_tile = get_current_tile(); - texture_region_editor->_edit_region(); - helper->selected_tile = get_current_tile(); - helper->_change_notify(""); + set_current_tile(-1); workspace->update(); } +void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { + int invalid_count = 0; + for (int i = 0; i < p_paths.size(); i++) { + Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i])); + if (texture_map.has(t->get_rid())) { + invalid_count++; + } else { + texture_list->add_item(t->get_path().get_file()); + texture_map.insert(t->get_rid(), t); + texture_list->set_item_metadata(texture_list->get_item_count() - 1, t->get_rid()); + } + } + update_texture_list_icon(); + texture_list->select(texture_list->get_item_count() - 1); + _on_texture_list_selected(texture_list->get_item_count() - 1); + if (invalid_count > 0) { + err_dialog->set_text(String::num(invalid_count, 0) + TTR(" file(s) was not added because was already on the list.")); + err_dialog->popup_centered(Size2(300, 60)); + } +} + void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { edit_mode = (EditMode)p_edit_mode; switch (edit_mode) { + case EDITMODE_REGION: { + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->hide(); + tools[BITMASK_PASTE]->hide(); + tools[BITMASK_CLEAR]->hide(); + tools[SHAPE_NEW_POLYGON]->hide(); + if (workspace_mode == WORKSPACE_EDIT) + tools[SHAPE_DELETE]->show(); + else + tools[SHAPE_DELETE]->hide(); + tools[SHAPE_KEEP_INSIDE_TILE]->hide(); + tools[TOOL_GRID_SNAP]->show(); + + tools[TOOL_SELECT]->set_pressed(true); + tools[TOOL_SELECT]->set_tooltip(TTR("Drag handles to edit Rect.\nClick on another Tile to edit it.")); + spin_priority->hide(); + } break; case EDITMODE_BITMASK: { - tool_containers[TOOLBAR_DUMMY]->show(); - tool_containers[TOOLBAR_BITMASK]->show(); - tool_containers[TOOLBAR_SHAPE]->hide(); + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->show(); + tools[BITMASK_PASTE]->show(); + tools[BITMASK_CLEAR]->show(); + tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_DELETE]->hide(); + tools[SHAPE_KEEP_INSIDE_TILE]->hide(); + tools[TOOL_GRID_SNAP]->hide(); + tools[TOOL_SELECT]->set_pressed(true); - tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off.")); + tools[TOOL_SELECT]->set_tooltip(TTR("LMB: set bit on.\nRMB: set bit off.\nClick on another Tile to edit it.")); spin_priority->hide(); } break; case EDITMODE_COLLISION: case EDITMODE_NAVIGATION: case EDITMODE_OCCLUSION: { - tool_containers[TOOLBAR_DUMMY]->show(); - tool_containers[TOOLBAR_BITMASK]->hide(); - tool_containers[TOOLBAR_SHAPE]->show(); - tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.")); + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->hide(); + tools[BITMASK_PASTE]->hide(); + tools[BITMASK_CLEAR]->hide(); + tools[SHAPE_NEW_POLYGON]->show(); + tools[SHAPE_DELETE]->show(); + tools[SHAPE_KEEP_INSIDE_TILE]->show(); + tools[TOOL_GRID_SNAP]->show(); + + tools[TOOL_SELECT]->set_tooltip(TTR("Select current edited sub-tile.\nClick on another Tile to edit it.")); spin_priority->hide(); - select_coord(edited_shape_coord); } break; default: { - tool_containers[TOOLBAR_DUMMY]->show(); - tool_containers[TOOLBAR_BITMASK]->hide(); - tool_containers[TOOLBAR_SHAPE]->hide(); + tools[TOOL_SELECT]->show(); + tools[BITMASK_COPY]->hide(); + tools[BITMASK_PASTE]->hide(); + tools[BITMASK_CLEAR]->hide(); + tools[SHAPE_NEW_POLYGON]->hide(); + tools[SHAPE_DELETE]->hide(); + tools[SHAPE_KEEP_INSIDE_TILE]->hide(); + tools[TOOL_GRID_SNAP]->show(); if (edit_mode == EDITMODE_ICON) { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.")); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to use as icon, this will be also used on invalid autotile bindings.\nClick on another Tile to edit it.")); spin_priority->hide(); } else { - tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.")); + tools[TOOL_SELECT]->set_tooltip(TTR("Select sub-tile to change its priority.\nClick on another Tile to edit it.")); spin_priority->show(); } } break; @@ -634,25 +650,52 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) { workspace->update(); } +void TileSetEditor::_on_workspace_mode_changed(int p_workspace_mode) { + workspace_mode = (WorkspaceMode)p_workspace_mode; + if (p_workspace_mode == WORKSPACE_EDIT) { + update_workspace_tile_mode(); + } else { + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->hide(); + } + tool_editmode[EDITMODE_REGION]->show(); + tool_editmode[EDITMODE_REGION]->set_pressed(true); + _on_edit_mode_changed(EDITMODE_REGION); + } +} + void TileSetEditor::_on_workspace_draw() { - if (get_current_tile() >= 0 && !tileset.is_null()) { + const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281); + const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373); + const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031); + + if (tileset.is_null()) + return; + if (!get_current_texture().is_valid()) + return; + + draw_highlight_current_tile(); + + draw_grid_snap(); + if (get_current_tile() >= 0) { int spacing = tileset->autotile_get_spacing(get_current_tile()); Vector2 size = tileset->autotile_get_size(get_current_tile()); Rect2i region = tileset->tile_get_region(get_current_tile()); - Color c(0.347214, 0.722656, 0.617063); switch (edit_mode) { case EDITMODE_ICON: { Vector2 coord = tileset->autotile_get_icon_coordinate(get_current_tile()); - draw_highlight_tile(coord); + draw_highlight_subtile(coord); } break; case EDITMODE_BITMASK: { - c = Color(1, 0, 0, 0.5); + Color c(1, 0, 0, 0.5); for (float x = 0; x < region.size.x / (spacing + size.x); x++) { for (float y = 0; y < region.size.y / (spacing + size.y); y++) { Vector2 coord(x, y); Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); + anchor += WORKSPACE_MARGIN; + anchor += region.position; uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (mask & TileSet::BIND_TOPLEFT) { @@ -702,9 +745,9 @@ void TileSetEditor::_on_workspace_draw() { case EDITMODE_COLLISION: case EDITMODE_OCCLUSION: case EDITMODE_NAVIGATION: { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { Vector2 coord = edited_shape_coord; - draw_highlight_tile(coord); + draw_highlight_subtile(coord); } draw_polygon_shapes(); draw_grid_snap(); @@ -723,89 +766,334 @@ void TileSetEditor::_on_workspace_draw() { } } spin_priority->set_suffix(" / " + String::num(total, 0)); - draw_highlight_tile(edited_shape_coord, queue_others); + draw_highlight_subtile(edited_shape_coord, queue_others); } break; } - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - float j = -size.x; //make sure to draw at 0 - while (j < region.size.x) { - j += size.x; - if (spacing <= 0) { - workspace->draw_line(Point2(j, 0), Point2(j, region.size.y), c); - } else { - workspace->draw_rect(Rect2(Point2(j, 0), Size2(spacing, region.size.y)), c); - } - j += spacing; - } - j = -size.y; //make sure to draw at 0 - while (j < region.size.y) { - j += size.y; - if (spacing <= 0) { - workspace->draw_line(Point2(0, j), Point2(region.size.x, j), c); - } else { - workspace->draw_rect(Rect2(Point2(0, j), Size2(region.size.x, spacing)), c); - } - j += spacing; + draw_tile_subdivision(get_current_tile(), Color(0.347214, 0.722656, 0.617063)); + } + + RID current_texture_rid = get_current_texture()->get_rid(); + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + int t_id = E->get(); + if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid && (t_id != get_current_tile() || edit_mode != EDITMODE_REGION)) { + Rect2i region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + draw_tile_subdivision(t_id, Color(0.347214, 0.722656, 0.617063, 0.5)); + workspace->draw_rect(region, c, false); + } + } + if (edit_mode == EDITMODE_REGION) { + if (workspace_mode != WORKSPACE_EDIT) { + Rect2i region = edited_region; + Color c; + if (workspace_mode == WORKSPACE_CREATE_SINGLE) + c = COLOR_SINGLE; + else if (workspace_mode == WORKSPACE_CREATE_AUTOTILE) + c = COLOR_AUTOTILE; + else if (workspace_mode == WORKSPACE_CREATE_ATLAS) + c = COLOR_ATLAS; + workspace->draw_rect(region, c, false); + draw_edited_region_subdivision(); + } else { + int t_id = get_current_tile(); + Rect2i region; + if (draw_edited_region) + region = edited_region; + else { + region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; } + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + if (draw_edited_region) + draw_edited_region_subdivision(); + else + draw_tile_subdivision(t_id, Color(0.347214, 0.722656, 0.617063, 1)); + workspace->draw_rect(region, c, false); } } workspace_overlay->update(); } +void TileSetEditor::_on_workspace_process() { + float a = tile_names_opacity; + if (Input::get_singleton()->is_key_pressed(KEY_ALT) || tools[VISIBLE_INFO]->is_pressed()) { + a += get_tree()->get_idle_process_time() * 2; + } else { + a -= get_tree()->get_idle_process_time() * 2; + } + + a = CLAMP(a, 0, 1); + if (a != tile_names_opacity) + workspace_overlay->update(); + tile_names_opacity = a; +} + void TileSetEditor::_on_workspace_overlay_draw() { + if (!tileset.is_valid()) + return; + if (!get_current_texture().is_valid()) + return; + + const Color COLOR_AUTOTILE = Color(0.266373, 0.565288, 0.988281); + const Color COLOR_SINGLE = Color(0.988281, 0.909323, 0.266373); + const Color COLOR_ATLAS = Color(0.78653, 0.812835, 0.832031); + + if (tile_names_opacity > 0) { + RID current_texture_rid = get_current_texture()->get_rid(); + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + int t_id = E->get(); + if (tileset->tile_get_texture(t_id)->get_rid() == current_texture_rid) { + Rect2i region = tileset->tile_get_region(t_id); + region.position += WORKSPACE_MARGIN; + region.position *= workspace->get_scale().x; + Color c; + if (tileset->tile_get_tile_mode(t_id) == TileSet::SINGLE_TILE) + c = COLOR_SINGLE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::AUTO_TILE) + c = COLOR_AUTOTILE; + else if (tileset->tile_get_tile_mode(t_id) == TileSet::ATLAS_TILE) + c = COLOR_ATLAS; + c.a = tile_names_opacity; + Ref<Font> font = get_font("font", "Label"); + region.set_size(font->get_string_size(tileset->tile_get_name(t_id))); + workspace_overlay->draw_rect(region, c); + region.position.y += region.size.y - 2; + c = Color(0.1, 0.1, 0.1, tile_names_opacity); + workspace_overlay->draw_string(font, region.position, tileset->tile_get_name(t_id), c); + } + } + } + int t_id = get_current_tile(); - if (t_id < 0 || !draw_handles) + if (t_id < 0) return; Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); - - for (int i = 0; i < current_shape.size(); i++) { - workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5); + if (draw_handles) { + for (int i = 0; i < current_shape.size(); i++) { + workspace_overlay->draw_texture(handle, current_shape[i] * workspace->get_scale().x - handle->get_size() * 0.5); + } } } #define MIN_DISTANCE_SQUARED 6 void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { + if (tileset.is_null()) + return; + if (!get_current_texture().is_valid()) + return; - if (get_current_tile() >= 0 && !tileset.is_null()) { - Ref<InputEventMouseButton> mb = p_ie; - Ref<InputEventMouseMotion> mm = p_ie; + static bool dragging; + static bool erasing; + draw_edited_region = false; - static bool dragging; - static bool erasing; + Rect2 current_tile_region = Rect2(); + if (get_current_tile() >= 0) { + current_tile_region = tileset->tile_get_region(get_current_tile()); + } + current_tile_region.position += WORKSPACE_MARGIN; + + Ref<InputEventMouseButton> mb = p_ie; + Ref<InputEventMouseMotion> mm = p_ie; + + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (!current_tile_region.has_point(mb->get_position())) { + List<int> *tiles = new List<int>(); + tileset->get_tile_list(tiles); + for (List<int>::Element *E = tiles->front(); E; E = E->next()) { + int t_id = E->get(); + if (get_current_texture()->get_rid() == tileset->tile_get_texture(t_id)->get_rid()) { + Rect2 r = tileset->tile_get_region(t_id); + r.position += WORKSPACE_MARGIN; + if (r.has_point(mb->get_position())) { + set_current_tile(t_id); + workspace->update(); + workspace_overlay->update(); + return; + } + } + } + } + } + } + // Drag Middle Mouse + if (mm.is_valid()) { + if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) { + Vector2 dragged(mm->get_relative().x, mm->get_relative().y); + scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x); + scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x); + } + } - int spacing = tileset->autotile_get_spacing(get_current_tile()); - Vector2 size = tileset->autotile_get_size(get_current_tile()); - switch (edit_mode) { - case EDITMODE_ICON: { - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); - tileset->autotile_set_icon_coordinate(get_current_tile(), coord); - Rect2 region = tileset->tile_get_region(get_current_tile()); - region.size = size; - coord.x *= (spacing + size.x); - coord.y *= (spacing + size.y); - region.position += coord; - tile_list->set_item_icon_region(current_item_index, region); - workspace->update(); + if (edit_mode == EDITMODE_REGION) { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (get_current_tile() >= 0 || workspace_mode != WORKSPACE_EDIT) { + dragging = true; + region_from = mb->get_position(); + edited_region = Rect2(region_from, Size2()); + workspace->update(); + workspace_overlay->update(); + return; + } + } else if (dragging && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { + dragging = false; + edited_region = Rect2(); + workspace->update(); + workspace_overlay->update(); + return; + } else if (dragging && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + dragging = false; + update_edited_region(mb->get_position()); + edited_region.position -= WORKSPACE_MARGIN; + if (!edited_region.has_no_area()) { + if (get_current_tile() >= 0 && workspace_mode == WORKSPACE_EDIT) { + tileset->tile_set_region(get_current_tile(), edited_region); + } else { + int t_id = tileset->get_last_unused_tile_id(); + tileset->create_tile(t_id); + tileset->tile_set_texture(t_id, get_current_texture()); + tileset->tile_set_region(t_id, edited_region); + tileset->tile_set_name(t_id, get_current_texture()->get_path().get_file() + " " + String::num(t_id, 0)); + if (workspace_mode != WORKSPACE_CREATE_SINGLE) { + tileset->autotile_set_size(t_id, snap_step); + tileset->autotile_set_spacing(t_id, snap_separation.x); + tileset->tile_set_tile_mode(t_id, workspace_mode == WORKSPACE_CREATE_AUTOTILE ? TileSet::AUTO_TILE : TileSet::ATLAS_TILE); + } + set_current_tile(t_id); + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); + _on_workspace_mode_changed(WORKSPACE_EDIT); } } - } break; - case EDITMODE_BITMASK: { - if (mb.is_valid()) { - if (mb->is_pressed()) { - if (dragging) { - return; + workspace->update(); + workspace_overlay->update(); + return; + } + } else if (mm.is_valid()) { + if (dragging) { + update_edited_region(mm->get_position()); + draw_edited_region = true; + workspace->update(); + workspace_overlay->update(); + return; + } + } + } + if (workspace_mode == WORKSPACE_EDIT) { + + if (get_current_tile() >= 0) { + int spacing = tileset->autotile_get_spacing(get_current_tile()); + Vector2 size = tileset->autotile_get_size(get_current_tile()); + switch (edit_mode) { + case EDITMODE_ICON: { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && current_tile_region.has_point(mb->get_position())) { + Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); + tileset->autotile_set_icon_coordinate(get_current_tile(), coord); + Rect2 region = tileset->tile_get_region(get_current_tile()); + region.size = size; + coord.x *= (spacing + size.x); + coord.y *= (spacing + size.y); + region.position += coord; + workspace->update(); + } + } + } break; + case EDITMODE_BITMASK: { + if (mb.is_valid()) { + if (mb->is_pressed()) { + if (dragging) { + return; + } + if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) { + dragging = true; + erasing = (mb->get_button_index() == BUTTON_RIGHT); + Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); + Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); + pos = mb->get_position() - (pos + current_tile_region.position); + uint16_t bit = 0; + if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { + if (pos.x < size.x / 2) { + if (pos.y < size.y / 2) { + bit = TileSet::BIND_TOPLEFT; + } else { + bit = TileSet::BIND_BOTTOMLEFT; + } + } else { + if (pos.y < size.y / 2) { + bit = TileSet::BIND_TOPRIGHT; + } else { + bit = TileSet::BIND_BOTTOMRIGHT; + } + } + } else { + if (pos.x < size.x / 3) { + if (pos.y < size.y / 3) { + bit = TileSet::BIND_TOPLEFT; + } else if (pos.y > (size.y / 3) * 2) { + bit = TileSet::BIND_BOTTOMLEFT; + } else { + bit = TileSet::BIND_LEFT; + } + } else if (pos.x > (size.x / 3) * 2) { + if (pos.y < size.y / 3) { + bit = TileSet::BIND_TOPRIGHT; + } else if (pos.y > (size.y / 3) * 2) { + bit = TileSet::BIND_BOTTOMRIGHT; + } else { + bit = TileSet::BIND_RIGHT; + } + } else { + if (pos.y < size.y / 3) { + bit = TileSet::BIND_TOP; + } else if (pos.y > (size.y / 3) * 2) { + bit = TileSet::BIND_BOTTOM; + } else { + bit = TileSet::BIND_CENTER; + } + } + } + uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); + if (erasing) { + mask &= ~bit; + } else { + mask |= bit; + } + tileset->autotile_set_bitmask(get_current_tile(), coord, mask); + workspace->update(); + } + } else { + if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) { + dragging = false; + erasing = false; + } } - if (mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) { - dragging = true; - erasing = (mb->get_button_index() == BUTTON_RIGHT); - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); + } + if (mm.is_valid()) { + if (dragging && current_tile_region.has_point(mm->get_position())) { + Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y))); Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - pos = mb->get_position() - pos; + pos = mm->get_position() - (pos + current_tile_region.position); uint16_t bit = 0; if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { if (pos.x < size.x / 2) { @@ -857,269 +1145,198 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { tileset->autotile_set_bitmask(get_current_tile(), coord, mask); workspace->update(); } - } else { - if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) { - dragging = false; - erasing = false; - } } - } - if (mm.is_valid()) { - if (dragging) { - Vector2 coord((int)(mm->get_position().x / (spacing + size.x)), (int)(mm->get_position().y / (spacing + size.y))); - Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y)); - pos = mm->get_position() - pos; - uint16_t bit = 0; - if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) { - if (pos.x < size.x / 2) { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPLEFT; - } else { - bit = TileSet::BIND_BOTTOMLEFT; - } - } else { - if (pos.y < size.y / 2) { - bit = TileSet::BIND_TOPRIGHT; - } else { - bit = TileSet::BIND_BOTTOMRIGHT; - } - } - } else { - if (pos.x < size.x / 3) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPLEFT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMLEFT; - } else { - bit = TileSet::BIND_LEFT; - } - } else if (pos.x > (size.x / 3) * 2) { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOPRIGHT; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOMRIGHT; - } else { - bit = TileSet::BIND_RIGHT; - } - } else { - if (pos.y < size.y / 3) { - bit = TileSet::BIND_TOP; - } else if (pos.y > (size.y / 3) * 2) { - bit = TileSet::BIND_BOTTOM; - } else { - bit = TileSet::BIND_CENTER; - } - } - } - uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord); - if (erasing) { - mask &= ~bit; - } else { - mask |= bit; - } - tileset->autotile_set_bitmask(get_current_tile(), coord, mask); - workspace->update(); + } break; + case EDITMODE_COLLISION: + case EDITMODE_OCCLUSION: + case EDITMODE_NAVIGATION: + case EDITMODE_PRIORITY: { + Vector2 shape_anchor = Vector2(0, 0); + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + shape_anchor = edited_shape_coord; + shape_anchor.x *= (size.x + spacing); + shape_anchor.y *= (size.y + spacing); } - } - } break; - case EDITMODE_COLLISION: - case EDITMODE_OCCLUSION: - case EDITMODE_NAVIGATION: - case EDITMODE_PRIORITY: { - Vector2 shape_anchor = Vector2(0, 0); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - shape_anchor = edited_shape_coord; - shape_anchor.x *= (size.x + spacing); - shape_anchor.y *= (size.y + spacing); - } - if (tools[TOOL_SELECT]->is_pressed()) { - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) { - for (int i = 0; i < current_shape.size(); i++) { - if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) { - dragging_point = i; - workspace->update(); - return; + shape_anchor += current_tile_region.position; + if (tools[TOOL_SELECT]->is_pressed()) { + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (edit_mode != EDITMODE_PRIORITY && current_shape.size() > 0) { + for (int i = 0; i < current_shape.size(); i++) { + if ((current_shape[i] - mb->get_position()).length_squared() <= MIN_DISTANCE_SQUARED) { + dragging_point = i; + workspace->update(); + return; + } } } - } - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - Vector2 coord((int)(mb->get_position().x / (spacing + size.x)), (int)(mb->get_position().y / (spacing + size.y))); - if (edited_shape_coord != coord) { - edited_shape_coord = coord; - edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); - edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); - bool found_collision_shape = false; - for (int i = 0; i < sd.size(); i++) { - if (sd[i].autotile_coord == coord) { - edited_collision_shape = sd[i].shape; - found_collision_shape = true; - break; + if ((tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) && current_tile_region.has_point(mb->get_position())) { + Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y))); + if (edited_shape_coord != coord) { + edited_shape_coord = coord; + edited_occlusion_shape = tileset->autotile_get_light_occluder(get_current_tile(), edited_shape_coord); + edited_navigation_shape = tileset->autotile_get_navigation_polygon(get_current_tile(), edited_shape_coord); + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); + bool found_collision_shape = false; + for (int i = 0; i < sd.size(); i++) { + if (sd[i].autotile_coord == coord) { + edited_collision_shape = sd[i].shape; + found_collision_shape = true; + break; + } } + if (!found_collision_shape) + edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); + select_coord(edited_shape_coord); } - if (!found_collision_shape) - edited_collision_shape = Ref<ConvexPolygonShape2D>(NULL); - select_coord(edited_shape_coord); } - } - workspace->update(); - } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (edit_mode == EDITMODE_COLLISION) { - if (dragging_point >= 0) { - dragging_point = -1; + workspace->update(); + } else if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (edit_mode == EDITMODE_COLLISION) { + if (dragging_point >= 0) { + dragging_point = -1; - Vector<Vector2> points; + Vector<Vector2> points; - for (int i = 0; i < current_shape.size(); i++) { - Vector2 p = current_shape[i]; - if (tools[SHAPE_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { - p = snap_point(p); + for (int i = 0; i < current_shape.size(); i++) { + Vector2 p = current_shape[i]; + if (tools[TOOL_GRID_SNAP]->is_pressed() || tools[SHAPE_KEEP_INSIDE_TILE]->is_pressed()) { + p = snap_point(p); + } + points.push_back(p - shape_anchor); } - points.push_back(p - shape_anchor); - } - edited_collision_shape->set_points(points); + edited_collision_shape->set_points(points); - workspace->update(); - } - } else if (edit_mode == EDITMODE_OCCLUSION) { - if (dragging_point >= 0) { - dragging_point = -1; - - PoolVector<Vector2> polygon; - polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); - - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; + workspace->update(); } + } else if (edit_mode == EDITMODE_OCCLUSION) { + if (dragging_point >= 0) { + dragging_point = -1; - w = PoolVector<Vector2>::Write(); - edited_occlusion_shape->set_polygon(polygon); + PoolVector<Vector2> polygon; + polygon.resize(current_shape.size()); + PoolVector<Vector2>::Write w = polygon.write(); - workspace->update(); - } - } else if (edit_mode == EDITMODE_NAVIGATION) { - if (dragging_point >= 0) { - dragging_point = -1; + for (int i = 0; i < current_shape.size(); i++) { + w[i] = current_shape[i] - shape_anchor; + } - PoolVector<Vector2> polygon; - Vector<int> indices; - polygon.resize(current_shape.size()); - PoolVector<Vector2>::Write w = polygon.write(); + w = PoolVector<Vector2>::Write(); + edited_occlusion_shape->set_polygon(polygon); - for (int i = 0; i < current_shape.size(); i++) { - w[i] = current_shape[i] - shape_anchor; - indices.push_back(i); + workspace->update(); } + } else if (edit_mode == EDITMODE_NAVIGATION) { + if (dragging_point >= 0) { + dragging_point = -1; + + PoolVector<Vector2> polygon; + Vector<int> indices; + polygon.resize(current_shape.size()); + PoolVector<Vector2>::Write w = polygon.write(); + + for (int i = 0; i < current_shape.size(); i++) { + w[i] = current_shape[i] - shape_anchor; + indices.push_back(i); + } - w = PoolVector<Vector2>::Write(); - edited_navigation_shape->set_vertices(polygon); - edited_navigation_shape->add_polygon(indices); - - workspace->update(); - } - } - } - } else if (mm.is_valid()) { - if (dragging_point >= 0) { - current_shape.set(dragging_point, snap_point(mm->get_position())); - workspace->update(); - } - } - } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) { + w = PoolVector<Vector2>::Write(); + edited_navigation_shape->set_vertices(polygon); + edited_navigation_shape->add_polygon(indices); - if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - Vector2 pos = mb->get_position(); - pos = snap_point(pos); - if (creating_shape) { - if (current_shape.size() > 0) { - if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) { - if (current_shape.size() > 2) { - close_shape(shape_anchor); - workspace->update(); - return; - } + workspace->update(); } } - current_shape.push_back(pos); + } + } else if (mm.is_valid()) { + if (dragging_point >= 0) { + current_shape.set(dragging_point, snap_point(mm->get_position())); workspace->update(); - } else { - int t_id = get_current_tile(); - if (t_id >= 0) { - if (edit_mode == EDITMODE_COLLISION) { - Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); - for (int i = 0; i < sd.size(); i++) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) { - Ref<ConvexPolygonShape2D> shape = sd[i].shape; - - if (!shape.is_null()) { - sd.remove(i); - tileset->tile_set_shapes(get_current_tile(), sd); - edited_collision_shape = Ref<Shape2D>(); - workspace->update(); - } - break; + } + } + } else if (tools[SHAPE_NEW_POLYGON]->is_pressed()) { + + if (mb.is_valid()) { + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + Vector2 pos = mb->get_position(); + pos = snap_point(pos); + if (creating_shape) { + if (current_shape.size() > 0) { + if ((pos - current_shape[0]).length_squared() <= MIN_DISTANCE_SQUARED) { + if (current_shape.size() > 2) { + close_shape(shape_anchor); + workspace->update(); + return; } } - } else if (edit_mode == EDITMODE_OCCLUSION) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); - for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + } + current_shape.push_back(pos); + workspace->update(); + } else { + int t_id = get_current_tile(); + if (t_id >= 0) { + if (edit_mode == EDITMODE_COLLISION) { + Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(t_id); + for (int i = 0; i < sd.size(); i++) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE || sd[i].autotile_coord == edited_shape_coord) { + Ref<ConvexPolygonShape2D> shape = sd[i].shape; + + if (!shape.is_null()) { + sd.remove(i); + tileset->tile_set_shapes(get_current_tile(), sd); + edited_collision_shape = Ref<Shape2D>(); + workspace->update(); + } break; } } - } else - tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>()); + } else if (edit_mode == EDITMODE_OCCLUSION) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + Map<Vector2, Ref<OccluderPolygon2D> > map = tileset->autotile_get_light_oclusion_map(t_id); + for (Map<Vector2, Ref<OccluderPolygon2D> >::Element *E = map.front(); E; E = E->next()) { + if (E->key() == edited_shape_coord) { + tileset->autotile_set_light_occluder(get_current_tile(), Ref<OccluderPolygon2D>(), edited_shape_coord); + break; + } + } + } else + tileset->tile_set_light_occluder(t_id, Ref<OccluderPolygon2D>()); - edited_occlusion_shape = Ref<OccluderPolygon2D>(); - workspace->update(); - } else if (edit_mode == EDITMODE_NAVIGATION) { - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { - Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); - for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { - if (E->key() == edited_shape_coord) { - tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); - break; + edited_occlusion_shape = Ref<OccluderPolygon2D>(); + workspace->update(); + } else if (edit_mode == EDITMODE_NAVIGATION) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + Map<Vector2, Ref<NavigationPolygon> > map = tileset->autotile_get_navigation_map(t_id); + for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = map.front(); E; E = E->next()) { + if (E->key() == edited_shape_coord) { + tileset->autotile_set_navigation_polygon(t_id, Ref<NavigationPolygon>(), edited_shape_coord); + break; + } } - } - } else - tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>()); - edited_navigation_shape = Ref<NavigationPolygon>(); - workspace->update(); + } else + tileset->tile_set_navigation_polygon(t_id, Ref<NavigationPolygon>()); + edited_navigation_shape = Ref<NavigationPolygon>(); + workspace->update(); + } } - } - creating_shape = true; - current_shape.resize(0); - current_shape.push_back(snap_point(pos)); + creating_shape = true; + current_shape.resize(0); + current_shape.push_back(snap_point(pos)); + } + } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) { + if (creating_shape) { + close_shape(shape_anchor); + } } - } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT && current_shape.size() > 2) { + } else if (mm.is_valid()) { if (creating_shape) { - close_shape(shape_anchor); + workspace->update(); } } - } else if (mm.is_valid()) { - if (creating_shape) { - workspace->update(); - } } - } - } break; - } - - //Drag Middle Mouse - if (mm.is_valid()) { - if (mm->get_button_mask() & BUTTON_MASK_MIDDLE) { - - Vector2 dragged(mm->get_relative().x, mm->get_relative().y); - scroll->set_h_scroll(scroll->get_h_scroll() - dragged.x * workspace->get_scale().x); - scroll->set_v_scroll(scroll->get_v_scroll() - dragged.y * workspace->get_scale().x); + } break; } } } @@ -1144,6 +1361,16 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { workspace->update(); } else { switch (edit_mode) { + case EDITMODE_REGION: { + if (workspace_mode == WORKSPACE_EDIT && get_current_tile() >= 0) { + tileset->remove_tile(get_current_tile()); + workspace->update(); + workspace_overlay->update(); + } + tool_workspacemode[WORKSPACE_EDIT]->set_pressed(true); + workspace_mode = WORKSPACE_EDIT; + update_workspace_tile_mode(); + } break; case EDITMODE_COLLISION: { if (!edited_collision_shape.is_null()) { Vector<TileSet::ShapeData> sd = tileset->tile_get_shapes(get_current_tile()); @@ -1186,22 +1413,22 @@ void TileSetEditor::_on_tool_clicked(int p_tool) { if (scale > 0.1) { scale /= 2; workspace->set_scale(Vector2(scale, scale)); - workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale); - workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale); + workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale); + workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale); } } else if (p_tool == ZOOM_1) { workspace->set_scale(Vector2(1, 1)); - workspace_container->set_custom_minimum_size(preview->get_region_rect().size); - workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size); + workspace_container->set_custom_minimum_size(workspace->get_rect().size); + workspace_overlay->set_custom_minimum_size(workspace->get_rect().size); } else if (p_tool == ZOOM_IN) { float scale = workspace->get_scale().x; scale *= 2; workspace->set_scale(Vector2(scale, scale)); - workspace_container->set_custom_minimum_size(preview->get_region_rect().size * scale); - workspace_overlay->set_custom_minimum_size(preview->get_region_rect().size * scale); + workspace_container->set_custom_minimum_size(workspace->get_rect().size * scale); + workspace_overlay->set_custom_minimum_size(workspace->get_rect().size * scale); } else if (p_tool == TOOL_SELECT) { if (creating_shape) { - //Cancel Creation + // Cancel Creation creating_shape = false; current_shape.resize(0); workspace->update(); @@ -1215,66 +1442,140 @@ void TileSetEditor::_on_priority_changed(float val) { } void TileSetEditor::_on_grid_snap_toggled(bool p_val) { - if (p_val) - hb_grid->show(); - else - hb_grid->hide(); + helper->set_snap_options_visible(p_val); workspace->update(); } -void TileSetEditor::_set_snap_step_x(float p_val) { - snap_step.x = p_val; +void TileSetEditor::_set_snap_step(Vector2 p_val) { + snap_step.x = CLAMP(p_val.x, 0, 256); + snap_step.y = CLAMP(p_val.y, 0, 256); workspace->update(); } -void TileSetEditor::_set_snap_step_y(float p_val) { - snap_step.y = p_val; +void TileSetEditor::_set_snap_off(Vector2 p_val) { + snap_offset.x = CLAMP(p_val.x, 0, 256 + WORKSPACE_MARGIN.x); + snap_offset.y = CLAMP(p_val.y, 0, 256 + WORKSPACE_MARGIN.y); workspace->update(); } -void TileSetEditor::_set_snap_off_x(float p_val) { - snap_offset.x = p_val; +void TileSetEditor::_set_snap_sep(Vector2 p_val) { + snap_separation.x = CLAMP(p_val.x, 0, 256); + snap_separation.y = CLAMP(p_val.y, 0, 256); workspace->update(); } -void TileSetEditor::_set_snap_off_y(float p_val) { - snap_offset.y = p_val; - workspace->update(); -} -void TileSetEditor::_set_snap_sep_x(float p_val) { - snap_separation.x = p_val; - workspace->update(); -} +void TileSetEditor::draw_highlight_current_tile() { -void TileSetEditor::_set_snap_sep_y(float p_val) { - snap_separation.y = p_val; - workspace->update(); + if (get_current_tile() >= 0) { + Rect2 region = tileset->tile_get_region(get_current_tile()); + region.position += WORKSPACE_MARGIN; + workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, region.position.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, region.position.y, region.position.x, region.size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(region.position.x + region.size.x, region.position.y, workspace->get_rect().size.x - region.position.x - region.size.x, region.size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, region.position.y + region.size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - region.size.y - region.position.y), Color(0.3, 0.3, 0.3, 0.3)); + } else { + workspace->draw_rect(Rect2(Point2(0, 0), workspace->get_rect().size), Color(0.3, 0.3, 0.3, 0.3)); + } } -void TileSetEditor::draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted) { +void TileSetEditor::draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted) { Vector2 size = tileset->autotile_get_size(get_current_tile()); int spacing = tileset->autotile_get_spacing(get_current_tile()); Rect2 region = tileset->tile_get_region(get_current_tile()); coord.x *= (size.x + spacing); coord.y *= (size.y + spacing); - workspace->draw_rect(Rect2(0, 0, region.size.x, coord.y), Color(0.5, 0.5, 0.5, 0.5)); - workspace->draw_rect(Rect2(0, coord.y, coord.x, size.y), Color(0.5, 0.5, 0.5, 0.5)); - workspace->draw_rect(Rect2(coord.x + size.x, coord.y, region.size.x - coord.x - size.x, size.y), Color(0.5, 0.5, 0.5, 0.5)); - workspace->draw_rect(Rect2(0, coord.y + size.y, region.size.x, region.size.y - size.y - coord.y), Color(0.5, 0.5, 0.5, 0.5)); + coord += region.position; + coord += WORKSPACE_MARGIN; + workspace->draw_rect(Rect2(0, 0, workspace->get_rect().size.x, coord.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, coord.y, coord.x, size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(coord.x + size.x, coord.y, workspace->get_rect().size.x - coord.x - size.x, size.y), Color(0.3, 0.3, 0.3, 0.3)); + workspace->draw_rect(Rect2(0, coord.y + size.y, workspace->get_rect().size.x, workspace->get_rect().size.y - size.y - coord.y), Color(0.3, 0.3, 0.3, 0.3)); coord += Vector2(1, 1) / workspace->get_scale().x; workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false); for (int i = 0; i < other_highlighted.size(); i++) { coord = other_highlighted[i]; coord.x *= (size.x + spacing); coord.y *= (size.y + spacing); + coord += region.position; + coord += WORKSPACE_MARGIN; coord += Vector2(1, 1) / workspace->get_scale().x; - workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0, 0), false); + workspace->draw_rect(Rect2(coord, size - Vector2(2, 2) / workspace->get_scale().x), Color(1, 0.5, 0.5), false); + } +} + +void TileSetEditor::draw_tile_subdivision(int p_id, Color p_color) const { + Color c = p_color; + if (tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE) { + Rect2 region = tileset->tile_get_region(p_id); + Size2 size = tileset->autotile_get_size(p_id); + int spacing = tileset->autotile_get_spacing(p_id); + float j = 0; + while (j < region.size.x) { + j += size.x; + if (spacing <= 0) { + workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(j, 0), region.position + WORKSPACE_MARGIN + Point2(j, region.size.y), c); + } else { + workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(j, 0), Size2(spacing, region.size.y)), c); + } + j += spacing; + } + j = 0; + while (j < region.size.y) { + j += size.y; + if (spacing <= 0) { + workspace->draw_line(region.position + WORKSPACE_MARGIN + Point2(0, j), region.position + WORKSPACE_MARGIN + Point2(region.size.x, j), c); + } else { + workspace->draw_rect(Rect2(region.position + WORKSPACE_MARGIN + Point2(0, j), Size2(region.size.x, spacing)), c); + } + j += spacing; + } + } +} + +void TileSetEditor::draw_edited_region_subdivision() const { + Color c = Color(0.347214, 0.722656, 0.617063, 1); + Rect2 region = edited_region; + Size2 size; + int spacing; + bool draw; + if (workspace_mode == WORKSPACE_EDIT) { + int p_id = get_current_tile(); + size = tileset->autotile_get_size(p_id); + spacing = tileset->autotile_get_spacing(p_id); + draw = tileset->tile_get_tile_mode(p_id) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(p_id) == TileSet::ATLAS_TILE; + } else { + size = snap_step; + spacing = snap_separation.x; + draw = workspace_mode != WORKSPACE_CREATE_SINGLE; + } + if (draw) { + + float j = 0; + while (j < region.size.x) { + j += size.x; + if (spacing <= 0) { + workspace->draw_line(region.position + Point2(j, 0), region.position + Point2(j, region.size.y), c); + } else { + workspace->draw_rect(Rect2(region.position + Point2(j, 0), Size2(spacing, region.size.y)), c); + } + j += spacing; + } + j = 0; + while (j < region.size.y) { + j += size.y; + if (spacing <= 0) { + workspace->draw_line(region.position + Point2(0, j), region.position + Point2(region.size.x, j), c); + } else { + workspace->draw_rect(Rect2(region.position + Point2(0, j), Size2(region.size.x, spacing)), c); + } + j += spacing; + } } } void TileSetEditor::draw_grid_snap() { - if (tools[SHAPE_GRID_SNAP]->is_pressed()) { + if (tools[TOOL_GRID_SNAP]->is_pressed()) { Color grid_color = Color(0.39, 0, 1, 0.2f); Size2 s = workspace->get_size(); @@ -1328,7 +1629,7 @@ void TileSetEditor::draw_polygon_shapes() { for (int i = 0; i < sd.size(); i++) { Vector2 coord = Vector2(0, 0); Vector2 anchor = Vector2(0, 0); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) { + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { coord = sd[i].autotile_coord; anchor = tileset->autotile_get_size(t_id); anchor.x += tileset->autotile_get_spacing(t_id); @@ -1336,6 +1637,8 @@ void TileSetEditor::draw_polygon_shapes() { anchor.x *= coord.x; anchor.y *= coord.y; } + anchor += WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(t_id).position; Ref<ConvexPolygonShape2D> shape = sd[i].shape; if (shape.is_valid()) { Color c_bg; @@ -1407,6 +1710,8 @@ void TileSetEditor::draw_polygon_shapes() { anchor.y += tileset->autotile_get_spacing(t_id); anchor.x *= coord.x; anchor.y *= coord.y; + anchor += WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(t_id).position; Ref<OccluderPolygon2D> shape = E->value(); if (shape.is_valid()) { Color c_bg; @@ -1483,6 +1788,8 @@ void TileSetEditor::draw_polygon_shapes() { anchor.y += tileset->autotile_get_spacing(t_id); anchor.x *= coord.x; anchor.y *= coord.y; + anchor += WORKSPACE_MARGIN; + anchor += tileset->tile_get_region(t_id).position; Ref<NavigationPolygon> shape = E->value(); if (shape.is_valid()) { Color c_bg; @@ -1558,10 +1865,10 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { shape->set_points(segments); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) tileset->tile_add_shape(get_current_tile(), shape, Transform2D(), false, edited_shape_coord); else - tileset->tile_set_shape(get_current_tile(), 0, shape); + tileset->tile_add_shape(get_current_tile(), shape, Transform2D()); edited_collision_shape = shape; } @@ -1582,7 +1889,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { w = PoolVector<Vector2>::Write(); shape->set_polygon(polygon); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) tileset->autotile_set_light_occluder(get_current_tile(), shape, edited_shape_coord); else tileset->tile_set_light_occluder(get_current_tile(), shape); @@ -1606,7 +1913,7 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { shape->set_vertices(polygon); shape->add_polygon(indices); - if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE) + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) tileset->autotile_set_navigation_polygon(get_current_tile(), shape, edited_shape_coord); else tileset->tile_set_navigation_polygon(get_current_tile(), shape); @@ -1619,6 +1926,8 @@ void TileSetEditor::close_shape(const Vector2 &shape_anchor) { void TileSetEditor::select_coord(const Vector2 &coord) { current_shape = PoolVector2Array(); + Rect2 current_tile_region = tileset->tile_get_region(get_current_tile()); + current_tile_region.position += WORKSPACE_MARGIN; if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (edited_collision_shape != tileset->tile_get_shape(get_current_tile(), 0)) edited_collision_shape = tileset->tile_get_shape(get_current_tile(), 0); @@ -1631,14 +1940,14 @@ void TileSetEditor::select_coord(const Vector2 &coord) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { for (int i = 0; i < edited_collision_shape->get_points().size(); i++) { - current_shape.push_back(edited_collision_shape->get_points()[i]); + current_shape.push_back(edited_collision_shape->get_points()[i] + current_tile_region.position); } } } else if (edit_mode == EDITMODE_OCCLUSION) { current_shape.resize(0); if (edited_occlusion_shape.is_valid()) { for (int i = 0; i < edited_occlusion_shape->get_polygon().size(); i++) { - current_shape.push_back(edited_occlusion_shape->get_polygon()[i]); + current_shape.push_back(edited_occlusion_shape->get_polygon()[i] + current_tile_region.position); } } } else if (edit_mode == EDITMODE_NAVIGATION) { @@ -1647,7 +1956,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { if (edited_navigation_shape->get_polygon_count() > 0) { PoolVector<Vector2> vertices = edited_navigation_shape->get_vertices(); for (int i = 0; i < edited_navigation_shape->get_polygon(0).size(); i++) { - current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]]); + current_shape.push_back(vertices[edited_navigation_shape->get_polygon(0)[i]] + current_tile_region.position); } } } @@ -1658,6 +1967,7 @@ void TileSetEditor::select_coord(const Vector2 &coord) { Vector2 shape_anchor = coord; shape_anchor.x *= (size.x + spacing); shape_anchor.y *= (size.y + spacing); + shape_anchor += current_tile_region.position; if (edit_mode == EDITMODE_COLLISION) { current_shape.resize(0); if (edited_collision_shape.is_valid()) { @@ -1684,6 +1994,9 @@ void TileSetEditor::select_coord(const Vector2 &coord) { } } } + workspace->update(); + workspace_container->update(); + helper->_change_notify(""); } Vector2 TileSetEditor::snap_point(const Vector2 &point) { @@ -1694,11 +2007,13 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { Vector2 anchor = coord; anchor.x *= (tile_size.x + spacing); anchor.y *= (tile_size.y + spacing); + anchor += tileset->tile_get_region(get_current_tile()).position; + anchor += WORKSPACE_MARGIN; Rect2 region(anchor, tile_size); if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) - region.position = Point2(0, 0); + region.position = tileset->tile_get_region(get_current_tile()).position + WORKSPACE_MARGIN; - if (tools[SHAPE_GRID_SNAP]->is_pressed()) { + if (tools[TOOL_GRID_SNAP]->is_pressed()) { p.x = Math::snap_scalar_seperation(snap_offset.x, snap_step.x, p.x, snap_separation.x); p.y = Math::snap_scalar_seperation(snap_offset.y, snap_step.y, p.y, snap_separation.y); } @@ -1715,211 +2030,332 @@ Vector2 TileSetEditor::snap_point(const Vector2 &point) { return p; } -void TileSetEditor::update_tile_list() { - int selected_tile = get_current_tile(); - - if (selected_tile < 0) - selected_tile = 0; +void TileSetEditor::update_texture_list() { + Ref<Texture> selected_texture = get_current_texture(); helper->set_tileset(tileset); - tile_list->clear(); List<int> ids; tileset->get_tile_list(&ids); for (List<int>::Element *E = ids.front(); E; E = E->next()) { - tile_list->add_item(tileset->tile_get_name(E->get())); - tile_list->set_item_metadata(tile_list->get_item_count() - 1, E->get()); - tile_list->set_item_icon(tile_list->get_item_count() - 1, tileset->tile_get_texture(E->get())); - Rect2 region = tileset->tile_get_region(E->get()); - if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) { - region.size = tileset->autotile_get_size(E->get()); - Vector2 pos = tileset->autotile_get_icon_coordinate(E->get()); - pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x); - pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y); - region.position += pos; + if (!texture_map.has(tileset->tile_get_texture(E->get())->get_rid())) { + texture_list->add_item(tileset->tile_get_texture(E->get())->get_path().get_file()); + texture_map.insert(tileset->tile_get_texture(E->get())->get_rid(), tileset->tile_get_texture(E->get())); + texture_list->set_item_metadata(texture_list->get_item_count() - 1, tileset->tile_get_texture(E->get())->get_rid()); } - tile_list->set_item_icon_region(tile_list->get_item_count() - 1, region); - tile_list->set_item_icon_modulate(tile_list->get_item_count() - 1, tileset->tile_get_modulate(E->get())); } - if (tile_list->get_item_count() > 0 && selected_tile < tile_list->get_item_count()) { - tile_list->select(selected_tile); - _on_tile_list_selected(selected_tile); + if (texture_list->get_item_count() > 0 && selected_texture.is_valid()) { + texture_list->select(texture_list->find_metadata(selected_texture->get_rid())); + if (texture_list->get_selected_items().size() > 0) + _on_texture_list_selected(texture_list->get_selected_items()[0]); + } else if (get_current_texture().is_valid()) { + _on_texture_list_selected(texture_list->find_metadata(get_current_texture()->get_rid())); + } else { + _on_texture_list_selected(-1); } + update_texture_list_icon(); helper->_change_notify(""); } -void TileSetEditor::update_tile_list_icon() { - List<int> ids; - tileset->get_tile_list(&ids); - int current_idx = 0; - for (List<int>::Element *E = ids.front(); E; E = E->next()) { - if (current_idx >= tile_list->get_item_count()) - break; - - Rect2 region = tileset->tile_get_region(E->get()); - if (tileset->tile_get_tile_mode(E->get()) == TileSet::AUTO_TILE) { - region.size = tileset->autotile_get_size(E->get()); - Vector2 pos = tileset->autotile_get_icon_coordinate(E->get()); - pos.x *= (tileset->autotile_get_spacing(E->get()) + region.size.x); - pos.y *= (tileset->autotile_get_spacing(E->get()) + region.size.y); - region.position += pos; - } - tile_list->set_item_metadata(current_idx, E->get()); - tile_list->set_item_icon(current_idx, tileset->tile_get_texture(E->get())); - tile_list->set_item_icon_region(current_idx, region); - tile_list->set_item_icon_modulate(current_idx, tileset->tile_get_modulate(E->get())); - tile_list->set_item_text(current_idx, tileset->tile_get_name(E->get())); - current_idx += 1; +void TileSetEditor::update_texture_list_icon() { + + for (int current_idx = 0; current_idx < texture_list->get_item_count(); current_idx++) { + RID rid = texture_list->get_item_metadata(current_idx); + texture_list->set_item_icon(current_idx, texture_map[rid]); + texture_list->set_item_icon_region(current_idx, Rect2(0, 0, 150, 100)); } - tile_list->update(); + texture_list->update(); } void TileSetEditor::update_workspace_tile_mode() { - if (get_current_tile() < 0) + + if (workspace_mode != WORKSPACE_EDIT) { + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->hide(); + } + tool_editmode[EDITMODE_REGION]->show(); + tool_editmode[EDITMODE_REGION]->set_pressed(true); + _on_edit_mode_changed(EDITMODE_REGION); + return; + } + + if (get_current_tile() < 0) { + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->hide(); + } + for (int i = 0; i < ZOOM_OUT; i++) { + tools[i]->hide(); + } return; + } + + for (int i = 0; i < EDITMODE_MAX; i++) { + tool_editmode[i]->show(); + } + if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::SINGLE_TILE) { if (tool_editmode[EDITMODE_ICON]->is_pressed() || tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { tool_editmode[EDITMODE_COLLISION]->set_pressed(true); - _on_edit_mode_changed(EDITMODE_COLLISION); - } else { - select_coord(Vector2(0, 0)); + edit_mode = EDITMODE_COLLISION; } + select_coord(Vector2(0, 0)); tool_editmode[EDITMODE_ICON]->hide(); tool_editmode[EDITMODE_BITMASK]->hide(); tool_editmode[EDITMODE_PRIORITY]->hide(); - property_editor->hide(); + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::AUTO_TILE || tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + if (edit_mode == EDITMODE_ICON) + select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); + else + select_coord(edited_shape_coord); + } else if (tileset->tile_get_tile_mode(get_current_tile()) == TileSet::ATLAS_TILE) { + if (tool_editmode[EDITMODE_PRIORITY]->is_pressed() || tool_editmode[EDITMODE_BITMASK]->is_pressed()) { + tool_editmode[EDITMODE_COLLISION]->set_pressed(true); + edit_mode = EDITMODE_COLLISION; + } + if (edit_mode == EDITMODE_ICON) + select_coord(tileset->autotile_get_icon_coordinate(get_current_tile())); + else + select_coord(edited_shape_coord); + + tool_editmode[EDITMODE_BITMASK]->hide(); + tool_editmode[EDITMODE_PRIORITY]->hide(); + } + _on_edit_mode_changed(edit_mode); +} + +void TileSetEditor::update_edited_region(const Vector2 &end_point) { + edited_region = Rect2(region_from, Size2()); + if (tools[TOOL_GRID_SNAP]->is_pressed()) { + Vector2 grid_coord; + grid_coord.x = Math::floor((region_from.x - snap_offset.x) / (snap_step.x + snap_separation.x)); + grid_coord.y = Math::floor((region_from.y - snap_offset.y) / (snap_step.y + snap_separation.y)); + grid_coord.x *= (snap_step.x + snap_separation.x); + grid_coord.y *= (snap_step.y + snap_separation.y); + grid_coord += snap_offset; + edited_region.expand_to(grid_coord); + grid_coord += snap_step; + edited_region.expand_to(grid_coord); + grid_coord.x = Math::floor((end_point.x - snap_offset.x) / (snap_step.x + snap_separation.x)); + grid_coord.y = Math::floor((end_point.y - snap_offset.y) / (snap_step.y + snap_separation.y)); + grid_coord.x *= (snap_step.x + snap_separation.x); + grid_coord.y *= (snap_step.y + snap_separation.y); + grid_coord += snap_offset; + edited_region.expand_to(grid_coord); + grid_coord += snap_step; + if (grid_coord.x < end_point.x) + grid_coord.x += snap_separation.x; + if (grid_coord.y < end_point.y) + grid_coord.y += snap_separation.y; + edited_region.expand_to(grid_coord); } else { - tool_editmode[EDITMODE_ICON]->show(); - tool_editmode[EDITMODE_BITMASK]->show(); - tool_editmode[EDITMODE_PRIORITY]->show(); - property_editor->show(); + edited_region.expand_to(end_point); } } -int TileSetEditor::get_current_tile() { - if (tile_list->get_selected_items().size() == 0) - return -1; +int TileSetEditor::get_current_tile() const { + return current_tile; +} + +void TileSetEditor::set_current_tile(int p_id) { + if (current_tile != p_id) { + current_tile = p_id; + helper->_change_notify(""); + select_coord(Vector2(0, 0)); + update_workspace_tile_mode(); + } +} + +Ref<Texture> TileSetEditor::get_current_texture() { + if (texture_list->get_selected_items().size() == 0) + return Ref<Texture>(); else - return tile_list->get_item_metadata(tile_list->get_selected_items()[0]); + return texture_map[texture_list->get_item_metadata(texture_list->get_selected_items()[0])]; } -void TileSetEditorHelper::set_tileset(const Ref<TileSet> &p_tileset) { +void TilesetEditorContext::set_tileset(const Ref<TileSet> &p_tileset) { tileset = p_tileset; } -bool TileSetEditorHelper::_set(const StringName &p_name, const Variant &p_value) { +void TilesetEditorContext::set_snap_options_visible(bool p_visible) { + snap_options_visible = p_visible; + _change_notify(""); +} - if (selected_tile < 0 || tileset.is_null()) - return false; +bool TilesetEditorContext::_set(const StringName &p_name, const Variant &p_value) { String name = p_name.operator String(); - bool v = false; - if (name == "bitmask_mode") { - tileset->set(String::num(selected_tile, 0) + "/autotile/bitmask_mode", p_value, &v); - } else if (name.left(7) == "layout/") { - tileset->set(String::num(selected_tile, 0) + "/autotile" + name.right(6), p_value, &v); - } - if (v) { - tileset->_change_notify("autotile"); + + if (name == "options_offset") { + Vector2 snap = p_value; + tileset_editor->_set_snap_off(snap + WORKSPACE_MARGIN); + return true; + } else if (name == "options_step") { + Vector2 snap = p_value; + tileset_editor->_set_snap_step(snap); + return true; + } else if (name == "options_separation") { + Vector2 snap = p_value; + tileset_editor->_set_snap_sep(snap); + return true; + } else if (p_name.operator String().left(5) == "tile_") { + String name = p_name.operator String().right(5); + bool v = false; + + if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) + return false; + + if (name == "autotile_bitmask_mode") { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", p_value, &v); + } else if (name == "subtile_size") { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", p_value, &v); + } else if (name == "subtile_spacing") { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", p_value, &v); + } else { + tileset->set(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, p_value, &v); + } + if (v) { + tileset->_change_notify(""); + tileset_editor->workspace->update(); + tileset_editor->workspace_overlay->update(); + } + return v; } - return v; -} -bool TileSetEditorHelper::_get(const StringName &p_name, Variant &r_ret) const { + tileset_editor->err_dialog->set_text(TTR("This property can't be changed.")); + tileset_editor->err_dialog->popup_centered(Size2(300, 60)); + return false; +} - if (selected_tile < 0 || tileset.is_null()) - return false; - if (!tileset->has_tile(selected_tile)) - return false; +bool TilesetEditorContext::_get(const StringName &p_name, Variant &r_ret) const { String name = p_name.operator String(); bool v = false; - if (name == "bitmask_mode") { - r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile/bitmask_mode", &v); - } else if (name.left(7) == "layout/") { - r_ret = tileset->get(String::num(selected_tile, 0) + "/autotile" + name.right(6), &v); + + if (name == "options_offset") { + r_ret = tileset_editor->snap_offset - WORKSPACE_MARGIN; + v = true; + } else if (name == "options_step") { + r_ret = tileset_editor->snap_step; + v = true; + } else if (name == "options_separation") { + r_ret = tileset_editor->snap_separation; + v = true; + } else if (name.left(5) == "tile_") { + name = name.right(5); + + if (tileset_editor->get_current_tile() < 0 || tileset.is_null()) + return false; + if (!tileset->has_tile(tileset_editor->get_current_tile())) + return false; + + if (name == "autotile_bitmask_mode") { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/bitmask_mode", &v); + } else if (name == "subtile_size") { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/tile_size", &v); + } else if (name == "subtile_spacing") { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/autotile/spacing", &v); + } else { + r_ret = tileset->get(String::num(tileset_editor->get_current_tile(), 0) + "/" + name, &v); + } + return v; + } else if (name == "selected_collision") { + r_ret = tileset_editor->edited_collision_shape; + v = true; + } else if (name == "selected_navigation") { + r_ret = tileset_editor->edited_navigation_shape; + v = true; + } else if (name == "selected_occlusion") { + r_ret = tileset_editor->edited_occlusion_shape; + v = true; } return v; } -void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const { - - if (selected_tile < 0 || tileset.is_null()) - return; +void TilesetEditorContext::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3 (minimal),3x3")); - p_list->push_back(PropertyInfo(Variant::VECTOR2, "layout/tile_size")); - p_list->push_back(PropertyInfo(Variant::INT, "layout/spacing", PROPERTY_HINT_RANGE, "0,256,1")); + if (snap_options_visible) { + p_list->push_back(PropertyInfo(Variant::NIL, "Snap Options", PROPERTY_HINT_NONE, "options_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_offset")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_step")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "options_separation")); + } + if (tileset_editor->get_current_tile() >= 0 && !tileset.is_null()) { + int id = tileset_editor->get_current_tile(); + p_list->push_back(PropertyInfo(Variant::NIL, "Selected Tile", PROPERTY_HINT_NONE, "tile_", PROPERTY_USAGE_GROUP)); + p_list->push_back(PropertyInfo(Variant::STRING, "tile_name")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_tex_offset")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "tile_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial")); + p_list->push_back(PropertyInfo(Variant::COLOR, "tile_modulate")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE")); + if (tileset->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { + p_list->push_back(PropertyInfo(Variant::INT, "tile_autotile_bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1")); + } else if (tileset->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_subtile_size")); + p_list->push_back(PropertyInfo(Variant::INT, "tile_subtile_spacing", PROPERTY_HINT_RANGE, "0, 256, 1")); + } + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_occluder_offset")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_navigation_offset")); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "tile_shape_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::INT, "tile_z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1")); + } + if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_COLLISION && tileset_editor->edited_collision_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_collision", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_collision_shape->get_class())); + } + if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_NAVIGATION && tileset_editor->edited_navigation_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_navigation", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_navigation_shape->get_class())); + } + if (tileset_editor->edit_mode == TileSetEditor::EDITMODE_OCCLUSION && tileset_editor->edited_occlusion_shape.is_valid()) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "selected_occlusion", PROPERTY_HINT_RESOURCE_TYPE, tileset_editor->edited_occlusion_shape->get_class())); + } } -TileSetEditorHelper::TileSetEditorHelper(TileSetEditor *p_tileset_editor) { - +TilesetEditorContext::TilesetEditorContext(TileSetEditor *p_tileset_editor) { tileset_editor = p_tileset_editor; - selected_tile = -1; } void TileSetEditorPlugin::edit(Object *p_node) { if (Object::cast_to<TileSet>(p_node)) { tileset_editor->edit(Object::cast_to<TileSet>(p_node)); - tileset_editor->show(); - tileset_editor->texture_region_editor->edit(p_node); - } else - tileset_editor->hide(); + editor->get_inspector()->edit(tileset_editor->helper); + } } bool TileSetEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("TileSet"); + return p_node->is_class("TileSet") || + p_node->is_class("TilesetEditorContext"); } void TileSetEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - tileset_editor->show(); - tileset_editor->menu->show(); tileset_editor_button->show(); - tileset_editor->side_panel->show(); if (tileset_editor_button->is_pressed()) { - tileset_editor->bottom_panel->show(); + tileset_editor->show(); } - texture_region_button->show(); - if (texture_region_button->is_pressed()) - tileset_editor->texture_region_editor->show(); + get_tree()->connect("idle_frame", tileset_editor, "_on_workspace_process"); } else { tileset_editor->hide(); - tileset_editor->menu->hide(); - tileset_editor->side_panel->hide(); - tileset_editor->bottom_panel->hide(); tileset_editor_button->hide(); - texture_region_button->hide(); - tileset_editor->texture_region_editor->hide(); + get_tree()->disconnect("idle_frame", tileset_editor, "_on_workspace_process"); } } TileSetEditorPlugin::TileSetEditorPlugin(EditorNode *p_node) { - + editor = p_node; tileset_editor = memnew(TileSetEditor(p_node)); - add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, tileset_editor); - tileset_editor->set_anchors_and_margins_preset(Control::PRESET_TOP_WIDE); - tileset_editor->set_end(Point2(0, 22)); - tileset_editor->hide(); - - tileset_editor->texture_region_editor = memnew(TextureRegionEditor(p_node)); - texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), tileset_editor->texture_region_editor); - texture_region_button->set_tooltip(TTR("Texture Region Editor")); - - tileset_editor->texture_region_editor->set_custom_minimum_size(Size2(0, 200)); - tileset_editor->texture_region_editor->hide(); - texture_region_button->hide(); + tileset_editor_button = + p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor); + tileset_editor_button->set_tooltip(TTR("Tile Set Editor")); - add_control_to_container(CONTAINER_CANVAS_EDITOR_SIDE, tileset_editor->side_panel); - tileset_editor->side_panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - tileset_editor->side_panel->set_custom_minimum_size(Size2(200, 0)); - tileset_editor->side_panel->hide(); - tileset_editor_button = p_node->add_bottom_panel_item(TTR("Tile Set"), tileset_editor->bottom_panel); + tileset_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); + tileset_editor->hide(); tileset_editor_button->hide(); } diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h index 4894d641a3..0c175e718c 100644 --- a/editor/plugins/tile_set_editor_plugin.h +++ b/editor/plugins/tile_set_editor_plugin.h @@ -33,21 +33,38 @@ #include "editor/editor_name_dialog.h" #include "editor/editor_node.h" -#include "editor/plugins/texture_region_editor_plugin.h" #include "scene/2d/sprite.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/tile_set.h" -class TileSetEditorHelper; +#define WORKSPACE_MARGIN Vector2(10, 10) +class TilesetEditorContext; -class TileSetEditor : public Control { +class TileSetEditor : public Panel { friend class TileSetEditorPlugin; - friend class TextureRegionEditor; + friend class TilesetEditorContext; - GDCLASS(TileSetEditor, Control); + GDCLASS(TileSetEditor, Panel) + + enum TextureToolButtons { + TOOL_TILESET_ADD_TEXTURE, + TOOL_TILESET_REMOVE_TEXTURE, + TOOL_TILESET_CREATE_SCENE, + TOOL_TILESET_MERGE_SCENE, + TOOL_TILESET_MAX + }; + + enum WorkspaceMode { + WORKSPACE_EDIT, + WORKSPACE_CREATE_SINGLE, + WORKSPACE_CREATE_AUTOTILE, + WORKSPACE_CREATE_ATLAS, + WORKSPACE_MODE_MAX + }; enum EditMode { + EDITMODE_REGION, EDITMODE_COLLISION, EDITMODE_OCCLUSION, EDITMODE_NAVIGATION, @@ -57,13 +74,6 @@ class TileSetEditor : public Control { EDITMODE_MAX }; - enum TileSetToolbar { - TOOLBAR_DUMMY, - TOOLBAR_BITMASK, - TOOLBAR_SHAPE, - TOOLBAR_MAX - }; - enum TileSetTools { TOOL_SELECT, BITMASK_COPY, @@ -71,17 +81,42 @@ class TileSetEditor : public Control { BITMASK_CLEAR, SHAPE_NEW_POLYGON, SHAPE_DELETE, - SHAPE_CREATE_FROM_BITMASK, - SHAPE_CREATE_FROM_NOT_BITMASK, SHAPE_KEEP_INSIDE_TILE, - SHAPE_GRID_SNAP, + TOOL_GRID_SNAP, ZOOM_OUT, ZOOM_1, ZOOM_IN, + VISIBLE_INFO, TOOL_MAX }; Ref<TileSet> tileset; + TilesetEditorContext *helper; + EditorNode *editor; + + ConfirmationDialog *cd; + AcceptDialog *err_dialog; + EditorFileDialog *texture_dialog; + + ItemList *texture_list; + int option; + ToolButton *tileset_toolbar_buttons[TOOL_TILESET_MAX]; + MenuButton *tileset_toolbar_tools; + Map<RID, Ref<Texture> > texture_map; + + bool creating_shape; + int dragging_point; + float tile_names_opacity; + Vector2 region_from; + Rect2 edited_region; + bool draw_edited_region; + Vector2 edited_shape_coord; + PoolVector2Array current_shape; + Map<Vector2, uint16_t> bitmask_map_copy; + + Vector2 snap_step; + Vector2 snap_offset; + Vector2 snap_separation; Ref<ConvexPolygonShape2D> edited_collision_shape; Ref<OccluderPolygon2D> edited_occlusion_shape; @@ -94,55 +129,19 @@ class TileSetEditor : public Control { bool draw_handles; Control *workspace_overlay; Control *workspace; + Button *tool_workspacemode[WORKSPACE_MODE_MAX]; Button *tool_editmode[EDITMODE_MAX]; - HBoxContainer *tool_containers[TOOLBAR_MAX]; HBoxContainer *toolbar; - HBoxContainer *hb_grid; ToolButton *tools[TOOL_MAX]; SpinBox *spin_priority; - SpinBox *sb_step_y; - SpinBox *sb_step_x; - SpinBox *sb_off_y; - SpinBox *sb_off_x; - SpinBox *sb_sep_y; - SpinBox *sb_sep_x; + WorkspaceMode workspace_mode; EditMode edit_mode; + int current_tile; - Vector2 snap_step; - Vector2 snap_offset; - Vector2 snap_separation; + void update_texture_list(); + void update_texture_list_icon(); - bool creating_shape; - int dragging_point; - Vector2 edited_shape_coord; - PoolVector2Array current_shape; - Map<Vector2, uint16_t> bitmask_map_copy; - - EditorNode *editor; - TextureRegionEditor *texture_region_editor; - Control *bottom_panel; - Control *side_panel; - ItemList *tile_list; - PropertyEditor *property_editor; - TileSetEditorHelper *helper; - - MenuButton *menu; - ConfirmationDialog *cd; - EditorNameDialog *nd; - AcceptDialog *err_dialog; - - enum { - - MENU_OPTION_ADD_ITEM, - MENU_OPTION_REMOVE_ITEM, - MENU_OPTION_CREATE_FROM_SCENE, - MENU_OPTION_MERGE_FROM_SCENE - }; - - int option; - void _menu_cbk(int p_option); - void _menu_confirm(); - void _name_dialog_confirm(const String &name); + Ref<Texture> get_current_texture(); static void _import_node(Node *p_node, Ref<TileSet> p_library); static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge); @@ -150,7 +149,6 @@ class TileSetEditor : public Control { protected: static void _bind_methods(); void _notification(int p_what); - virtual void _changed_callback(Object *p_changed, const char *p_prop); public: void edit(const Ref<TileSet> &p_tileset); @@ -160,53 +158,61 @@ public: ~TileSetEditor(); private: - void _on_tile_list_selected(int p_index); + void _on_tileset_toolbar_button_pressed(int p_index); + void _on_tileset_toolbar_confirm(); + void _on_texture_list_selected(int p_index); + void _on_textures_added(const PoolStringArray &p_paths); void _on_edit_mode_changed(int p_edit_mode); + void _on_workspace_mode_changed(int p_workspace_mode); void _on_workspace_overlay_draw(); void _on_workspace_draw(); + void _on_workspace_process(); void _on_workspace_input(const Ref<InputEvent> &p_ie); void _on_tool_clicked(int p_tool); void _on_priority_changed(float val); void _on_grid_snap_toggled(bool p_val); - void _set_snap_step_x(float p_val); - void _set_snap_step_y(float p_val); - void _set_snap_off_x(float p_val); - void _set_snap_off_y(float p_val); - void _set_snap_sep_x(float p_val); - void _set_snap_sep_y(float p_val); - - void initialize_bottom_editor(); - void draw_highlight_tile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>()); + void _set_snap_step(Vector2 p_val); + void _set_snap_off(Vector2 p_val); + void _set_snap_sep(Vector2 p_val); + + void draw_highlight_current_tile(); + void draw_highlight_subtile(Vector2 coord, const Vector<Vector2> &other_highlighted = Vector<Vector2>()); + void draw_tile_subdivision(int p_id, Color p_color) const; + void draw_edited_region_subdivision() const; void draw_grid_snap(); void draw_polygon_shapes(); void close_shape(const Vector2 &shape_anchor); void select_coord(const Vector2 &coord); Vector2 snap_point(const Vector2 &point); - void update_tile_list(); - void update_tile_list_icon(); void update_workspace_tile_mode(); + void update_edited_region(const Vector2 &end_point); - int get_current_tile(); + int get_current_tile() const; + void set_current_tile(int p_id); }; -class TileSetEditorHelper : public Object { +class TilesetEditorContext : public Object { friend class TileSetEditor; - GDCLASS(TileSetEditorHelper, Object); + GDCLASS(TilesetEditorContext, Object); Ref<TileSet> tileset; TileSetEditor *tileset_editor; - int selected_tile; + bool snap_options_visible; public: void set_tileset(const Ref<TileSet> &p_tileset); +private: + void set_snap_options_visible(bool p_visible); + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; - TileSetEditorHelper(TileSetEditor *p_tileset_editor); +public: + TilesetEditorContext(TileSetEditor *p_tileset_editor); }; class TileSetEditorPlugin : public EditorPlugin { @@ -214,11 +220,9 @@ class TileSetEditorPlugin : public EditorPlugin { GDCLASS(TileSetEditorPlugin, EditorPlugin); TileSetEditor *tileset_editor; + Button *tileset_editor_button; EditorNode *editor; - ToolButton *tileset_editor_button; - ToolButton *texture_region_button; - public: virtual String get_name() const { return "TileSet"; } bool has_main_screen() const { return false; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 9218fed907..63e89b78ea 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -119,6 +119,9 @@ void VisualShaderEditor::_update_graph() { if (updating) return; + if (visual_shader.is_null()) + return; + graph->set_scroll_ofs(visual_shader->get_graph_offset() * EDSCALE); VisualShader::Type type = VisualShader::Type(edit_type->get_selected()); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 95d39953cf..aad9258ed9 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -915,12 +915,6 @@ void ProjectManager::_update_project_buttons() { CanvasItem *item = Object::cast_to<CanvasItem>(scroll_children->get_child(i)); item->update(); - - Button *show = Object::cast_to<Button>(item->get_node(NodePath("project/path_box/show"))); - if (show) { - String current = item->get_meta("name"); - show->set_visible(selected_list.has(current)); - } } bool empty_selection = selected_list.empty(); @@ -1316,7 +1310,6 @@ void ProjectManager::_load_recent_projects() { path_hb->add_child(show); show->connect("pressed", this, "_show_project", varray(path)); show->set_tooltip(TTR("Show In File Manager")); - show->set_visible(false); Label *fpath = memnew(Label(path)); fpath->set_name("path"); @@ -1757,6 +1750,8 @@ ProjectManager::ProjectManager() { editor_set_scale(custom_display_scale); } break; } + + OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE)); } FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); @@ -1782,7 +1777,6 @@ ProjectManager::ProjectManager() { String cp; cp += 0xA9; - cp += '0'; OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2018 Juan Linietsky, Ariel Manzur & Godot Contributors"); HBoxContainer *top_hb = memnew(HBoxContainer); @@ -1825,7 +1819,7 @@ ProjectManager::ProjectManager() { project_filter = memnew(ProjectListFilter); search_box->add_child(project_filter); project_filter->connect("filter_changed", this, "_load_recent_projects"); - project_filter->set_custom_minimum_size(Size2(250, 10)); + project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE); search_tree_vb->add_child(search_box); PanelContainer *pc = memnew(PanelContainer); @@ -2023,18 +2017,6 @@ void ProjectListFilter::_setup_filters() { filter_option->add_item(TTR("Path")); } -void ProjectListFilter::_command(int p_command) { - switch (p_command) { - - case CMD_CLEAR_FILTER: { - if (search_box->get_text() != "") { - search_box->clear(); - emit_signal("filter_changed"); - } - } break; - } -} - void ProjectListFilter::_search_text_changed(const String &p_newtext) { emit_signal("filter_changed"); } @@ -2057,13 +2039,14 @@ void ProjectListFilter::_filter_option_selected(int p_idx) { void ProjectListFilter::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) - clear_search_button->set_icon(get_icon("Close", "EditorIcons")); + if (p_what == NOTIFICATION_ENTER_TREE) { + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + } } void ProjectListFilter::_bind_methods() { - ClassDB::bind_method(D_METHOD("_command"), &ProjectListFilter::_command); ClassDB::bind_method(D_METHOD("_search_text_changed"), &ProjectListFilter::_search_text_changed); ClassDB::bind_method(D_METHOD("_filter_option_selected"), &ProjectListFilter::_filter_option_selected); @@ -2088,8 +2071,4 @@ ProjectListFilter::ProjectListFilter() { search_box->connect("text_changed", this, "_search_text_changed"); search_box->set_h_size_flags(SIZE_EXPAND_FILL); add_child(search_box); - - clear_search_button = memnew(ToolButton); - clear_search_button->connect("pressed", this, "_command", make_binds(CMD_CLEAR_FILTER)); - add_child(clear_search_button); } diff --git a/editor/project_manager.h b/editor/project_manager.h index a9d23b1f71..ad21e00b0d 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -128,13 +128,8 @@ class ProjectListFilter : public HBoxContainer { private: friend class ProjectManager; - enum Command { - CMD_CLEAR_FILTER, - }; - OptionButton *filter_option; LineEdit *search_box; - ToolButton *clear_search_button; enum FilterOption { FILTER_NAME, @@ -142,7 +137,6 @@ private: }; FilterOption _current_filter; - void _command(int p_command); void _search_text_changed(const String &p_newtext); void _setup_filters(); void _filter_option_selected(int p_idx); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 2b2e03ce38..ea697f5da2 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -81,7 +81,8 @@ void ProjectSettingsEditor::_notification(int p_what) { globals_editor->edit(ProjectSettings::get_singleton()); search_button->set_icon(get_icon("Search", "EditorIcons")); - clear_button->set_icon(get_icon("Close", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); action_add_error->add_color_override("font_color", get_color("error_color", "Editor")); @@ -119,7 +120,8 @@ void ProjectSettingsEditor::_notification(int p_what) { case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { search_button->set_icon(get_icon("Search", "EditorIcons")); - clear_button->set_icon(get_icon("Close", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); action_add_error->add_color_override("font_color", get_color("error_color", "Editor")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_KEY), get_icon("Keyboard", "EditorIcons")); popup_add->set_item_icon(popup_add->get_item_index(INPUT_JOY_BUTTON), get_icon("JoyButton", "EditorIcons")); @@ -213,10 +215,8 @@ void ProjectSettingsEditor::_action_edited() { undo_redo->create_action(TTR("Change Action deadzone")); undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, new_action); - undo_redo->add_do_method(this, "_update_actions"); undo_redo->add_do_method(this, "_settings_changed"); undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", name, old_action); - undo_redo->add_undo_method(this, "_update_actions"); undo_redo->add_undo_method(this, "_settings_changed"); undo_redo->commit_action(); } @@ -1591,15 +1591,6 @@ void ProjectSettingsEditor::_toggle_search_bar(bool p_pressed) { } } -void ProjectSettingsEditor::_clear_search_box() { - - if (search_box->get_text() == "") - return; - - search_box->clear(); - globals_editor->get_inspector()->update_tree(); -} - void ProjectSettingsEditor::set_plugins_page() { tab_container->set_current_tab(plugin_settings->get_index()); @@ -1662,7 +1653,6 @@ void ProjectSettingsEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_translation_filter_option_changed"), &ProjectSettingsEditor::_translation_filter_option_changed); ClassDB::bind_method(D_METHOD("_translation_filter_mode_changed"), &ProjectSettingsEditor::_translation_filter_mode_changed); - ClassDB::bind_method(D_METHOD("_clear_search_box"), &ProjectSettingsEditor::_clear_search_box); ClassDB::bind_method(D_METHOD("_toggle_search_bar"), &ProjectSettingsEditor::_toggle_search_bar); ClassDB::bind_method(D_METHOD("_copy_to_platform_about_to_show"), &ProjectSettingsEditor::_copy_to_platform_about_to_show); @@ -1753,10 +1743,6 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) { search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); search_bar->add_child(search_box); - clear_button = memnew(ToolButton); - search_bar->add_child(clear_button); - clear_button->connect("pressed", this, "_clear_search_box"); - globals_editor = memnew(SectionedInspector); props_base->add_child(globals_editor); globals_editor->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo()); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 3b74ae1909..b738c4ae20 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -69,7 +69,6 @@ class ProjectSettingsEditor : public AcceptDialog { HBoxContainer *search_bar; Button *search_button; LineEdit *search_box; - ToolButton *clear_button; HBoxContainer *add_prop_bar; AcceptDialog *message; @@ -158,7 +157,6 @@ class ProjectSettingsEditor : public AcceptDialog { void _translation_filter_mode_changed(int p_mode); void _toggle_search_bar(bool p_pressed); - void _clear_search_box(); void _copy_to_platform_about_to_show(); diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp index 907bb50f7e..d2101f1e00 100644 --- a/editor/quick_open.cpp +++ b/editor/quick_open.cpp @@ -258,6 +258,9 @@ void EditorQuickOpen::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { connect("confirmed", this, "_confirmed"); + + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); } } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 73a9c8ac1a..d17bcef92b 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -119,7 +119,7 @@ void SceneTreeDock::instance(const String &p_file) { if (!edited_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("OK :(")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("No parent to instance a child at.")); accept->popup_centered_minsize(); return; @@ -164,7 +164,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node Ref<PackedScene> sdata = ResourceLoader::load(p_files[i]); if (!sdata.is_valid()) { current_option = -1; - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error loading scene from %s"), p_files[i])); accept->popup_centered_minsize(); error = true; @@ -174,7 +174,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instanced_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i])); accept->popup_centered_minsize(); error = true; @@ -233,7 +233,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) { Ref<PackedScene> sdata = ResourceLoader::load(p_file); if (!sdata.is_valid()) { - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error loading scene from %s"), p_file)); accept->popup_centered_minsize(); return; @@ -241,7 +241,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!instanced_scene) { - accept->get_ok()->set_text(TTR("Ugh")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file)); accept->popup_centered_minsize(); return; @@ -413,7 +413,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (scene_tree->get_selected() == edited_scene) { current_option = -1; - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); break; @@ -474,7 +474,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (editor_selection->is_selected(edited_scene)) { current_option = -1; - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); break; @@ -544,7 +544,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (editor_selection->is_selected(edited_scene)) { current_option = -1; - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on the tree root.")); accept->popup_centered_minsize(); break; @@ -631,7 +631,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *scene = editor_data->get_edited_scene_root(); if (!scene) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done without a scene.")); accept->popup_centered_minsize(); break; @@ -640,7 +640,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.size() != 1) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); break; @@ -649,14 +649,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *tocopy = selection.front()->get(); if (tocopy == scene) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can not perform with the root node.")); accept->popup_centered_minsize(); break; } if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation can't be done on instanced scenes.")); accept->popup_centered_minsize(); break; @@ -797,18 +797,38 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } break; case TOOL_CREATE_2D_SCENE: case TOOL_CREATE_3D_SCENE: - case TOOL_CREATE_USER_INTERFACE: { + case TOOL_CREATE_USER_INTERFACE: + case TOOL_CREATE_FAVORITE: { Node *new_node; - switch (p_tool) { - case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break; - case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break; - case TOOL_CREATE_USER_INTERFACE: { - Control *node = memnew(Control); - node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs. - new_node = node; - } break; + if (TOOL_CREATE_FAVORITE == p_tool) { + String name = selected_favorite_root.get_slicec(' ', 0); + if (ScriptServer::is_global_class(name)) { + new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_base(name))); + Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); + if (new_node && script.is_valid()) { + new_node->set_script(script.get_ref_ptr()); + new_node->set_name(name); + } + } 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); + } + } else { + switch (p_tool) { + case TOOL_CREATE_2D_SCENE: new_node = memnew(Node2D); break; + case TOOL_CREATE_3D_SCENE: new_node = memnew(Spatial); break; + case TOOL_CREATE_USER_INTERFACE: { + Control *node = memnew(Control); + node->set_anchors_and_margins_preset(PRESET_WIDE); //more useful for resizable UIs. + new_node = node; + + } break; + } } editor_data->get_undo_redo().create_action("New Scene Root"); @@ -862,39 +882,67 @@ void SceneTreeDock::_notification(int p_what) { button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons")); button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons")); - filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed"); - create_root_dialog->add_child(memnew(Label(TTR("Create Root Node:")))); + // create_root_dialog + HBoxContainer *top_row = memnew(HBoxContainer); + top_row->set_name("NodeShortcutsTopRow"); + top_row->set_h_size_flags(SIZE_EXPAND_FILL); + top_row->add_child(memnew(Label(TTR("Create Root Node:")))); + top_row->add_spacer(); - Button *button_2d = memnew(Button); - create_root_dialog->add_child(button_2d); + ToolButton *node_shortcuts_toggle = memnew(ToolButton); + node_shortcuts_toggle->set_name("NodeShortcutsToggle"); + node_shortcuts_toggle->set_icon(get_icon("Favorites", "EditorIcons")); + node_shortcuts_toggle->set_toggle_mode(true); + node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection")); + node_shortcuts_toggle->set_anchors_and_margins_preset(Control::PRESET_CENTER_RIGHT); + node_shortcuts_toggle->connect("pressed", this, "_update_create_root_dialog"); + top_row->add_child(node_shortcuts_toggle); + + create_root_dialog->add_child(top_row); + VBoxContainer *node_shortcuts = memnew(VBoxContainer); + node_shortcuts->set_name("NodeShortcuts"); + + VBoxContainer *beginner_node_shortcuts = memnew(VBoxContainer); + beginner_node_shortcuts->set_name("BeginnerNodeShortcuts"); + node_shortcuts->add_child(beginner_node_shortcuts); + + Button *button_2d = memnew(Button); + beginner_node_shortcuts->add_child(button_2d); button_2d->set_text(TTR("2D Scene")); button_2d->set_icon(get_icon("Node2D", "EditorIcons")); button_2d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_2D_SCENE, false)); Button *button_3d = memnew(Button); - create_root_dialog->add_child(button_3d); + beginner_node_shortcuts->add_child(button_3d); button_3d->set_text(TTR("3D Scene")); button_3d->set_icon(get_icon("Spatial", "EditorIcons")); button_3d->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_3D_SCENE, false)); Button *button_ui = memnew(Button); - create_root_dialog->add_child(button_ui); + beginner_node_shortcuts->add_child(button_ui); button_ui->set_text(TTR("User Interface")); button_ui->set_icon(get_icon("Control", "EditorIcons")); button_ui->connect("pressed", this, "_tool_selected", make_binds(TOOL_CREATE_USER_INTERFACE, false)); + VBoxContainer *favorite_node_shortcuts = memnew(VBoxContainer); + favorite_node_shortcuts->set_name("FavoriteNodeShortcuts"); + node_shortcuts->add_child(favorite_node_shortcuts); + Button *button_custom = memnew(Button); - create_root_dialog->add_child(button_custom); + node_shortcuts->add_child(button_custom); button_custom->set_text(TTR("Custom Node")); button_custom->set_icon(get_icon("Add", "EditorIcons")); button_custom->connect("pressed", this, "_tool_selected", make_binds(TOOL_NEW, false)); - create_root_dialog->add_spacer(); - + node_shortcuts->add_spacer(); + create_root_dialog->add_child(node_shortcuts); + _update_create_root_dialog(); } break; case NOTIFICATION_ENTER_TREE: { @@ -910,7 +958,8 @@ void SceneTreeDock::_notification(int p_what) { button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons")); button_clear_script->set_icon(get_icon("ScriptRemove", "EditorIcons")); - filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + filter->set_right_icon(get_icon("Search", "EditorIcons")); + filter->set_clear_button_enabled(true); } break; case NOTIFICATION_PROCESS: { @@ -1249,7 +1298,7 @@ bool SceneTreeDock::_validate_no_foreign() { if (E->get() != edited_scene && E->get()->get_owner() != edited_scene) { - accept->get_ok()->set_text(TTR("Makes Sense!")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can't operate on nodes from a foreign scene!")); accept->popup_centered_minsize(); return false; @@ -1257,7 +1306,7 @@ bool SceneTreeDock::_validate_no_foreign() { if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) { - accept->get_ok()->set_text(TTR("Makes Sense!")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Can't operate on nodes the current scene inherits from!")); accept->popup_centered_minsize(); return false; @@ -1737,7 +1786,7 @@ void SceneTreeDock::_new_scene_from(String p_file) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.size() != 1) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("This operation requires a single selected node.")); accept->popup_centered_minsize(); return; @@ -1755,7 +1804,7 @@ void SceneTreeDock::_new_scene_from(String p_file) { memdelete(copy); if (err != OK) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied.")); accept->popup_centered_minsize(); return; @@ -1767,14 +1816,14 @@ void SceneTreeDock::_new_scene_from(String p_file) { err = ResourceSaver::save(p_file, sdata, flg); if (err != OK) { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Error saving scene.")); accept->popup_centered_minsize(); return; } _replace_with_branch_scene(p_file, base); } else { - accept->get_ok()->set_text(TTR("I see...")); + accept->get_ok()->set_text(TTR("OK")); accept->set_text(TTR("Error duplicating scene to save it.")); accept->popup_centered_minsize(); return; @@ -2148,6 +2197,67 @@ void SceneTreeDock::_local_tree_selected() { edit_local->set_pressed(true); } +void SceneTreeDock::_update_create_root_dialog() { + + BaseButton *toggle = Object::cast_to<BaseButton>(create_root_dialog->get_node(String("NodeShortcutsTopRow/NodeShortcutsToggle"))); + Node *node_shortcuts = create_root_dialog->get_node(String("NodeShortcuts")); + + if (!toggle || !node_shortcuts) + return; + + Control *beginner_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("BeginnerNodeShortcuts"))); + Control *favorite_nodes = Object::cast_to<Control>(node_shortcuts->get_node(String("FavoriteNodeShortcuts"))); + + if (!beginner_nodes || !favorite_nodes) + return; + + EditorSettings::get_singleton()->set_setting("_use_favorites_root_selection", toggle->is_pressed()); + EditorSettings::get_singleton()->save(); + if (toggle->is_pressed()) { + + for (int i = 0; i < favorite_nodes->get_child_count(); i++) { + favorite_nodes->get_child(i)->queue_delete(); + } + + FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ); + + if (f) { + + while (!f->eof_reached()) { + String l = f->get_line().strip_edges(); + + if (l != String()) { + Button *button = memnew(Button); + favorite_nodes->add_child(button); + button->set_text(TTR(l)); + String name = l.get_slicec(' ', 0); + if (ScriptServer::is_global_class(name)) + name = ScriptServer::get_global_class_base(name); + button->set_icon(get_icon(name, "EditorIcons")); + button->connect("pressed", this, "_favorite_root_selected", make_binds(l)); + } + } + + memdelete(f); + } + + if (!favorite_nodes->is_visible_in_tree()) { + favorite_nodes->show(); + beginner_nodes->hide(); + } + } else { + if (!beginner_nodes->is_visible_in_tree()) { + beginner_nodes->show(); + favorite_nodes->hide(); + } + } +} + +void SceneTreeDock::_favorite_root_selected(const String &p_class) { + selected_favorite_root = p_class; + _tool_selected(TOOL_CREATE_FAVORITE, false); +} + void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tool_selected"), &SceneTreeDock::_tool_selected, DEFVAL(false)); @@ -2176,6 +2286,8 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_remote_tree_selected"), &SceneTreeDock::_remote_tree_selected); ClassDB::bind_method(D_METHOD("_local_tree_selected"), &SceneTreeDock::_local_tree_selected); ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button); + ClassDB::bind_method(D_METHOD("_favorite_root_selected"), &SceneTreeDock::_favorite_root_selected); + ClassDB::bind_method(D_METHOD("_update_create_root_dialog"), &SceneTreeDock::_update_create_root_dialog); ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); @@ -2301,6 +2413,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel create_dialog->set_base_type("Node"); add_child(create_dialog); create_dialog->connect("create", this, "_create"); + create_dialog->connect("favorites_updated", this, "_update_create_root_dialog"); + EditorFileSystem::get_singleton()->connect("script_classes_updated", create_dialog, "_save_and_update_favorite_list"); rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo())); add_child(rename_dialog); @@ -2347,11 +2461,12 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel clear_inherit_confirm = memnew(ConfirmationDialog); clear_inherit_confirm->set_text(TTR("Clear Inheritance? (No Undo!)")); - clear_inherit_confirm->get_ok()->set_text(TTR("Clear!")); + clear_inherit_confirm->get_ok()->set_text(TTR("Clear")); add_child(clear_inherit_confirm); set_process_input(true); set_process(true); EDITOR_DEF("interface/editors/show_scene_tree_root_selection", true); + EDITOR_DEF("_use_favorites_root_selection", false); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 57f4759747..34a7c98d11 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -86,6 +86,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_CREATE_2D_SCENE, TOOL_CREATE_3D_SCENE, TOOL_CREATE_USER_INTERFACE, + TOOL_CREATE_FAVORITE, }; @@ -141,6 +142,7 @@ class SceneTreeDock : public VBoxContainer { EditorNode *editor; VBoxContainer *create_root_dialog; + String selected_favorite_root; void _add_children_to_popup(Object *p_obj, int p_depth); @@ -201,6 +203,9 @@ class SceneTreeDock : public VBoxContainer { void _remote_tree_selected(); void _local_tree_selected(); + void _update_create_root_dialog(); + void _favorite_root_selected(const String &p_class); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index e483fde4bc..bd661ade53 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1198,7 +1198,7 @@ void ScriptEditorDebugger::start() { int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); if (server->listen(remote_port) != OK) { - EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true); + EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), EditorLog::MSG_TYPE_ERROR); return; } diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index fe379703e5..4ebba73cb3 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -114,22 +114,6 @@ void EditorSettingsDialog::popup_edit_settings() { _focus_current_search_box(); } -void EditorSettingsDialog::_clear_search_box() { - - if (search_box->get_text() == "") - return; - - search_box->clear(); - inspector->get_inspector()->update_tree(); -} - -void EditorSettingsDialog::_clear_shortcut_search_box() { - if (shortcut_search_box->get_text() == "") - return; - - shortcut_search_box->clear(); -} - void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) { shortcut_filter = p_filter; _update_shortcuts(); @@ -198,10 +182,10 @@ void EditorSettingsDialog::_unhandled_input(const Ref<InputEvent> &p_event) { void EditorSettingsDialog::_update_icons() { - search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - shortcut_search_box->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); - clear_button->set_icon(get_icon("Close", "EditorIcons")); - shortcut_clear_button->set_icon(get_icon("Close", "EditorIcons")); + search_box->set_right_icon(get_icon("Search", "EditorIcons")); + search_box->set_clear_button_enabled(true); + shortcut_search_box->set_right_icon(get_icon("Search", "EditorIcons")); + shortcut_search_box->set_clear_button_enabled(true); restart_close_button->set_icon(get_icon("Close", "EditorIcons")); restart_container->add_style_override("panel", get_stylebox("bg", "Tree")); @@ -411,8 +395,6 @@ void EditorSettingsDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_settings_save"), &EditorSettingsDialog::_settings_save); ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed); ClassDB::bind_method(D_METHOD("_settings_property_edited"), &EditorSettingsDialog::_settings_property_edited); - ClassDB::bind_method(D_METHOD("_clear_search_box"), &EditorSettingsDialog::_clear_search_box); - ClassDB::bind_method(D_METHOD("_clear_shortcut_search_box"), &EditorSettingsDialog::_clear_shortcut_search_box); ClassDB::bind_method(D_METHOD("_shortcut_button_pressed"), &EditorSettingsDialog::_shortcut_button_pressed); ClassDB::bind_method(D_METHOD("_filter_shortcuts"), &EditorSettingsDialog::_filter_shortcuts); ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts); @@ -451,10 +433,6 @@ EditorSettingsDialog::EditorSettingsDialog() { search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); hbc->add_child(search_box); - clear_button = memnew(ToolButton); - hbc->add_child(clear_button); - clear_button->connect("pressed", this, "_clear_search_box"); - inspector = memnew(SectionedInspector); //inspector->hide_top_label(); inspector->get_inspector()->set_use_filter(true); @@ -500,10 +478,6 @@ EditorSettingsDialog::EditorSettingsDialog() { hbc->add_child(shortcut_search_box); shortcut_search_box->connect("text_changed", this, "_filter_shortcuts"); - shortcut_clear_button = memnew(ToolButton); - hbc->add_child(shortcut_clear_button); - shortcut_clear_button->connect("pressed", this, "_clear_shortcut_search_box"); - shortcuts = memnew(Tree); tab_shortcuts->add_child(shortcuts, true); shortcuts->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/settings_config_dialog.h b/editor/settings_config_dialog.h index 6cf2eb6bdf..37d32e401d 100644 --- a/editor/settings_config_dialog.h +++ b/editor/settings_config_dialog.h @@ -52,8 +52,6 @@ class EditorSettingsDialog : public AcceptDialog { LineEdit *search_box; LineEdit *shortcut_search_box; - ToolButton *clear_button; - ToolButton *shortcut_clear_button; SectionedInspector *inspector; Timer *timer; diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index c450c0fd4c..64fdc778d0 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -47,7 +47,10 @@ // Keep small children away from this file. // It's so ugly it will eat them alive -#define HANDLE_HALF_SIZE 0.05 +// The previous comment is kept only for historical reasons. +// No children will be harmed by the viewing of this file... hopefully. + +#define HANDLE_HALF_SIZE 9.5 bool EditorSpatialGizmo::can_draw() const { return is_editable(); @@ -85,11 +88,37 @@ void EditorSpatialGizmo::clear() { void EditorSpatialGizmo::redraw() { - if (get_script_instance() && get_script_instance()->has_method("redraw")) - get_script_instance()->call("redraw"); + ERR_FAIL_COND(!gizmo_plugin); + gizmo_plugin->redraw(this); +} + +String EditorSpatialGizmo::get_handle_name(int p_idx) const { + ERR_FAIL_COND_V(!gizmo_plugin, ""); + return gizmo_plugin->get_handle_name(this, p_idx); +} + +Variant EditorSpatialGizmo::get_handle_value(int p_idx) { + ERR_FAIL_COND_V(!gizmo_plugin, Variant()); + return gizmo_plugin->get_handle_value(this, p_idx); +} + +void EditorSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { + ERR_FAIL_COND(!gizmo_plugin); + return gizmo_plugin->set_handle(this, p_idx, p_camera, p_point); +} + +void EditorSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + ERR_FAIL_COND(!gizmo_plugin); + return gizmo_plugin->commit_handle(this, p_idx, p_restore, p_cancel); +} + +void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) { + + ERR_FAIL_NULL(p_node); + spatial_node = p_node; } -void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) { +void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base, bool p_hidden) { instance = VS::get_singleton()->instance_create2(mesh->get_rid(), p_base->get_world()->get_scenario()); VS::get_singleton()->instance_attach_object_instance_id(instance, p_base->get_instance_id()); @@ -98,7 +127,8 @@ void EditorSpatialGizmo::Instance::create_instance(Spatial *p_base) { if (extra_margin) VS::get_singleton()->instance_set_extra_visibility_margin(instance, 1); VS::get_singleton()->instance_geometry_set_cast_shadows_setting(instance, VS::SHADOW_CASTING_SETTING_OFF); - VS::get_singleton()->instance_set_layer_mask(instance, 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER); //gizmos are 26 + int layer = p_hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER; + VS::get_singleton()->instance_set_layer_mask(instance, layer); //gizmos are 26 } void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard, const RID &p_skeleton) { @@ -110,7 +140,7 @@ void EditorSpatialGizmo::add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard ins.mesh = p_mesh; ins.skeleton = p_skeleton; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } @@ -159,7 +189,7 @@ void EditorSpatialGizmo::add_lines(const Vector<Vector3> &p_lines, const Ref<Mat ins.billboard = p_billboard; ins.mesh = mesh; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } @@ -210,7 +240,7 @@ void EditorSpatialGizmo::add_unscaled_billboard(const Ref<Material> &p_material, ins.unscaled = true; ins.billboard = true; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } @@ -233,7 +263,7 @@ void EditorSpatialGizmo::add_collision_segments(const Vector<Vector3> &p_lines) } } -void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_billboard, bool p_secondary) { +void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<Material> &p_material, bool p_billboard, bool p_secondary) { billboard_handle = p_billboard; @@ -257,7 +287,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi for (int i = 0; i < p_handles.size(); i++) { Color col(1, 1, 1, 1); - if (is_gizmo_handle_highlighted(i)) + if (gizmo_plugin->is_gizmo_handle_highlighted(this, i)) col = Color(0, 0, 1, 0.9); if (SpatialEditor::get_singleton()->get_over_gizmo_handle() != i) @@ -268,10 +298,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi } a[VS::ARRAY_COLOR] = colors; mesh->add_surface_from_arrays(Mesh::PRIMITIVE_POINTS, a); - if (p_billboard) - mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material_billboard); - else - mesh->surface_set_material(0, SpatialEditorGizmos::singleton->handle2_material); + mesh->surface_set_material(0, p_material); if (p_billboard) { float md = 0; @@ -288,7 +315,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi ins.billboard = p_billboard; ins.extra_margin = true; if (valid) { - ins.create_instance(spatial_node); + ins.create_instance(spatial_node, hidden); VS::get_singleton()->instance_set_transform(ins.instance, spatial_node->get_global_transform()); } instances.push_back(ins); @@ -330,17 +357,13 @@ void EditorSpatialGizmo::add_solid_box(Ref<Material> &p_material, Vector3 p_size add_mesh(m); } -void EditorSpatialGizmo::set_spatial_node(Spatial *p_node) { - - ERR_FAIL_NULL(p_node); - spatial_node = p_node; -} - bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum) { ERR_FAIL_COND_V(!spatial_node, false); ERR_FAIL_COND_V(!valid, false); + if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false; + if (selectable_icon_size > 0.0f) { Vector3 origin = spatial_node->get_global_transform().get_origin(); @@ -413,7 +436,9 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, ERR_FAIL_COND_V(!spatial_node, false); ERR_FAIL_COND_V(!valid, false); - if (r_gizmo_handle) { + if (hidden && !gizmo_plugin->is_selectable_when_hidden()) return false; + + if (r_gizmo_handle && !hidden) { Transform t = spatial_node->get_global_transform(); t.orthonormalize(); @@ -428,7 +453,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 hpos = t.xform(secondary_handles[i]); Vector2 p = p_camera->unproject_position(hpos); - if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) { + + if (p.distance_to(p_point) < HANDLE_HALF_SIZE) { real_t dp = p_camera->get_transform().origin.distance_to(hpos); if (dp < min_d) { @@ -453,7 +479,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 hpos = t.xform(handles[i]); Vector2 p = p_camera->unproject_position(hpos); - if (p.distance_to(p_point) < SpatialEditorGizmos::singleton->handle_t->get_width() * 0.6) { + + if (p.distance_to(p_point) < HANDLE_HALF_SIZE) { real_t dp = p_camera->get_transform().origin.distance_to(hpos); if (dp < min_d) { @@ -504,6 +531,8 @@ bool EditorSpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, rect.set_position(center - rect.get_size() / 2.0); if (rect.has_point(p_point)) { + r_pos = t.origin; + r_normal = -p_camera->project_ray_normal(p_point); return true; } @@ -597,7 +626,7 @@ void EditorSpatialGizmo::create() { for (int i = 0; i < instances.size(); i++) { - instances.write[i].create_instance(spatial_node); + instances.write[i].create_instance(spatial_node, hidden); } transform(); @@ -624,96 +653,21 @@ void EditorSpatialGizmo::free() { instances.write[i].instance = RID(); } + clear(); + valid = false; } -Ref<SpatialMaterial> EditorSpatialGizmo::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { - - String name = p_name; - - if (!is_editable()) { - name += "@readonly"; - } else if (is_selected()) { - name += "@selected"; - } - - if (SpatialEditorGizmos::singleton->material_cache.has(name)) { - return SpatialEditorGizmos::singleton->material_cache[name]; - } - - Color color = p_color; - - if (!is_editable()) { - color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); - } - if (!is_selected()) { - color.a *= 0.3; - } - - Ref<SpatialMaterial> line_material; - line_material.instance(); - line_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - line_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - if (p_use_vertex_color) { - line_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - line_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - } - - if (p_billboard) { - line_material->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); +void EditorSpatialGizmo::set_hidden(bool p_hidden) { + hidden = p_hidden; + int layer = hidden ? 0 : 1 << SpatialEditorViewport::GIZMO_EDIT_LAYER; + for (int i = 0; i < instances.size(); ++i) { + VS::get_singleton()->instance_set_layer_mask(instances[i].instance, layer); } - - if (p_on_top && is_selected()) { - line_material->set_on_top_of_alpha(); - } - - line_material->set_albedo(color); - - SpatialEditorGizmos::singleton->material_cache[name] = line_material; - - return line_material; } -Ref<SpatialMaterial> EditorSpatialGizmo::create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top, const Color &p_albedo) { - - String name = p_name; - - if (!is_editable()) { - name += "@readonly"; - } else if (is_selected()) { - name += "@selected"; - } - - if (SpatialEditorGizmos::singleton->material_cache.has(name)) { - return SpatialEditorGizmos::singleton->material_cache[name]; - } - - Color color = p_albedo; - - if (!is_editable()) { - color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/instanced"); - } else if (!is_selected()) { - color.a *= 0.3; - } - - Ref<SpatialMaterial> icon; - icon.instance(); - icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - icon->set_albedo(color); - icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, p_texture); - icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); - icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - if (p_on_top && is_selected()) { - icon->set_on_top_of_alpha(); - } - - SpatialEditorGizmos::singleton->material_cache[name] = icon; - - return icon; +void EditorSpatialGizmo::set_plugin(EditorSpatialGizmoPlugin *p_plugin) { + gizmo_plugin = p_plugin; } void EditorSpatialGizmo::_bind_methods() { @@ -726,6 +680,7 @@ void EditorSpatialGizmo::_bind_methods() { ClassDB::bind_method(D_METHOD("add_handles", "handles", "billboard", "secondary"), &EditorSpatialGizmo::add_handles, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_spatial_node", "node"), &EditorSpatialGizmo::_set_spatial_node); ClassDB::bind_method(D_METHOD("clear"), &EditorSpatialGizmo::clear); + ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorSpatialGizmo::set_hidden); BIND_VMETHOD(MethodInfo("redraw")); BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index"))); @@ -743,12 +698,17 @@ void EditorSpatialGizmo::_bind_methods() { EditorSpatialGizmo::EditorSpatialGizmo() { valid = false; billboard_handle = false; + hidden = false; base = NULL; + selected = false; + instanced = false; spatial_node = NULL; + gizmo_plugin = NULL; } EditorSpatialGizmo::~EditorSpatialGizmo() { + if (gizmo_plugin != NULL) gizmo_plugin->unregister_gizmo(this); clear(); } @@ -761,7 +721,30 @@ Vector3 EditorSpatialGizmo::get_handle_pos(int p_idx) const { //// light gizmo -String LightSpatialGizmo::get_handle_name(int p_idx) const { +LightSpatialGizmoPlugin::LightSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2)); + + create_material("lines", gizmo_color); + create_material("lines_billboard", gizmo_color, true); + + create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); + create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons")); + create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons")); + + create_handle_material("handles"); + create_handle_material("handles_billboard", true); +} + +bool LightSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Light>(p_spatial) != NULL; +} + +String LightSpatialGizmoPlugin::get_name() const { + return "Lights"; +} + +String LightSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { if (p_idx == 0) return "Radius"; @@ -769,8 +752,9 @@ String LightSpatialGizmo::get_handle_name(int p_idx) const { return "Aperture"; } -Variant LightSpatialGizmo::get_handle_value(int p_idx) const { +Variant LightSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); if (p_idx == 0) return light->get_param(Light::PARAM_RANGE); if (p_idx == 1) @@ -808,8 +792,9 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec return a * 180.0 / Math_PI; } -void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void LightSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); Transform gt = light->get_global_transform(); gt.orthonormalize(); Transform gi = gt.affine_inverse(); @@ -848,8 +833,9 @@ void LightSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_ } } -void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void LightSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); if (p_cancel) { light->set_param(p_idx == 0 ? Light::PARAM_RANGE : Light::PARAM_SPOT_ANGLE, p_restore); @@ -871,14 +857,16 @@ void LightSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool } } -void LightSpatialGizmo::redraw() { +void LightSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Light *light = Object::cast_to<Light>(p_gizmo->get_spatial_node()); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/light"); + p_gizmo->clear(); if (Object::cast_to<DirectionalLight>(light)) { - Ref<Material> material = create_material("light_directional_material", gizmo_color); - Ref<Material> icon = create_icon_material("light_directional_icon", SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); + Ref<Material> material = get_material("lines", p_gizmo); + Ref<Material> icon = get_material("light_directional_icon", p_gizmo); const int arrow_points = 7; const float arrow_length = 1.5; @@ -909,16 +897,15 @@ void LightSpatialGizmo::redraw() { } } - add_lines(lines, material); - add_collision_segments(lines); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_unscaled_billboard(icon, 0.05); } if (Object::cast_to<OmniLight>(light)) { - Ref<Material> material = create_material("light_omni_material", gizmo_color, true); - Ref<Material> icon = create_icon_material("light_omni_icon", SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons")); - clear(); + Ref<Material> material = get_material("lines_billboard", p_gizmo); + Ref<Material> icon = get_material("light_omni_icon", p_gizmo); OmniLight *on = Object::cast_to<OmniLight>(light); @@ -941,29 +928,27 @@ void LightSpatialGizmo::redraw() { points.push_back(Vector3(b.x, b.y, 0)); } - add_lines(points, material, true); - add_collision_segments(points); + p_gizmo->add_lines(points, material, true); + p_gizmo->add_collision_segments(points); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_unscaled_billboard(icon, 0.05); Vector<Vector3> handles; handles.push_back(Vector3(r, 0, 0)); - add_handles(handles, true); + p_gizmo->add_handles(handles, get_material("handles_billboard"), true); } if (Object::cast_to<SpotLight>(light)) { - Ref<Material> material = create_material("light_spot_material", gizmo_color); - Ref<Material> icon = create_icon_material("light_spot_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpotLight", "EditorIcons")); - - clear(); + Ref<Material> material = get_material("lines", p_gizmo); + Ref<Material> icon = get_material("light_spot_icon", p_gizmo); Vector<Vector3> points; - SpotLight *on = Object::cast_to<SpotLight>(light); + SpotLight *sl = Object::cast_to<SpotLight>(light); - float r = on->get_param(Light::PARAM_RANGE); - float w = r * Math::sin(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE))); - float d = r * Math::cos(Math::deg2rad(on->get_param(Light::PARAM_SPOT_ANGLE))); + float r = sl->get_param(Light::PARAM_RANGE); + float w = r * Math::sin(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE))); + float d = r * Math::cos(Math::deg2rad(sl->get_param(Light::PARAM_SPOT_ANGLE))); for (int i = 0; i < 360; i++) { @@ -985,7 +970,7 @@ void LightSpatialGizmo::redraw() { points.push_back(Vector3(0, 0, -r)); points.push_back(Vector3()); - add_lines(points, material); + p_gizmo->add_lines(points, material); Vector<Vector3> handles; handles.push_back(Vector3(0, 0, -r)); @@ -1017,33 +1002,45 @@ void LightSpatialGizmo::redraw() { collision_segments.push_back(Vector3(0, 0, -r)); collision_segments.push_back(Vector3()); - add_handles(handles); - add_collision_segments(collision_segments); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); + p_gizmo->add_collision_segments(collision_segments); + p_gizmo->add_unscaled_billboard(icon, 0.05); } } -LightSpatialGizmo::LightSpatialGizmo(Light *p_light) { +////// + +//// player gizmo +AudioStreamPlayer3DSpatialGizmoPlugin::AudioStreamPlayer3DSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); - light = p_light; - set_spatial_node(p_light); + create_icon_material("stream_player_3d_icon", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons")); + create_material("stream_player_3d_material", gizmo_color); + create_handle_material("handles"); } -////// +bool AudioStreamPlayer3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<AudioStreamPlayer3D>(p_spatial) != NULL; +} -//// player gizmo +String AudioStreamPlayer3DSpatialGizmoPlugin::get_name() const { + return "AudioStreamPlayer3D"; +} -String AudioStreamPlayer3DSpatialGizmo::get_handle_name(int p_idx) const { +String AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { return "Emission Radius"; } -Variant AudioStreamPlayer3DSpatialGizmo::get_handle_value(int p_idx) const { - +Variant AudioStreamPlayer3DSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); return player->get_emission_angle(); } -void AudioStreamPlayer3DSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void AudioStreamPlayer3DSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); Transform gt = player->get_global_transform(); gt.orthonormalize(); @@ -1081,7 +1078,9 @@ void AudioStreamPlayer3DSpatialGizmo::set_handle(int p_idx, Camera *p_camera, co } } -void AudioStreamPlayer3DSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void AudioStreamPlayer3DSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); if (p_cancel) { @@ -1097,16 +1096,17 @@ void AudioStreamPlayer3DSpatialGizmo::commit_handle(int p_idx, const Variant &p_ } } -void AudioStreamPlayer3DSpatialGizmo::redraw() { +void AudioStreamPlayer3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); - Ref<Material> icon = create_icon_material("stream_player_3d_material", SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer", "EditorIcons")); + Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo); if (player->is_emission_angle_enabled()) { - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/stream_player_3d"); - Ref<Material> material = create_material("stream_player_3d_material", gizmo_color); + Ref<Material> material = get_material("stream_player_3d_material", p_gizmo); float pc = player->get_emission_angle(); @@ -1138,27 +1138,40 @@ void AudioStreamPlayer3DSpatialGizmo::redraw() { points.write[200 + i * 2 + 1] = Vector3(); } - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); Vector<Vector3> handles; float ha = Math::deg2rad(player->get_emission_angle()); handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha))); - add_handles(handles); + p_gizmo->add_handles(handles, get_material("handles")); } - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_unscaled_billboard(icon, 0.05); } -AudioStreamPlayer3DSpatialGizmo::AudioStreamPlayer3DSpatialGizmo(AudioStreamPlayer3D *p_player) { +////// + +CameraSpatialGizmoPlugin::CameraSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); - player = p_player; - set_spatial_node(p_player); + create_material("camera_material", gizmo_color); + create_icon_material("camera_icon", SpatialEditor::get_singleton()->get_icon("GizmoCamera", "EditorIcons")); + create_handle_material("handles"); } -////// +bool CameraSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Camera>(p_spatial) != NULL; +} + +String CameraSpatialGizmoPlugin::get_name() const { + return "Camera"; +} -String CameraSpatialGizmo::get_handle_name(int p_idx) const { +String CameraSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { return "FOV"; @@ -1166,7 +1179,10 @@ String CameraSpatialGizmo::get_handle_name(int p_idx) const { return "Size"; } } -Variant CameraSpatialGizmo::get_handle_value(int p_idx) const { + +Variant CameraSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { return camera->get_fov(); @@ -1175,7 +1191,10 @@ Variant CameraSpatialGizmo::get_handle_value(int p_idx) const { return camera->get_size(); } } -void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { + +void CameraSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); Transform gt = camera->get_global_transform(); gt.orthonormalize(); @@ -1201,7 +1220,10 @@ void CameraSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p camera->set("size", d); } } -void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { + +void CameraSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); if (camera->get_projection() == Camera::PROJECTION_PERSPECTIVE) { @@ -1231,16 +1253,17 @@ void CameraSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool } } -void CameraSpatialGizmo::redraw() { +void CameraSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + Camera *camera = Object::cast_to<Camera>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector3> lines; Vector<Vector3> handles; - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/camera"); - Ref<Material> material = create_material("camera_material", gizmo_color); - Ref<Material> icon = create_icon_material("camera_icon", SpatialEditor::get_singleton()->get_icon("GizmoCamera", "EditorIcons")); + Ref<Material> material = get_material("camera_material", p_gizmo); + Ref<Material> icon = get_material("camera_icon", p_gizmo); switch (camera->get_projection()) { @@ -1310,71 +1333,81 @@ void CameraSpatialGizmo::redraw() { } break; } - add_lines(lines, material); - add_collision_segments(lines); - add_unscaled_billboard(icon, 0.05); - add_handles(handles); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); } -CameraSpatialGizmo::CameraSpatialGizmo(Camera *p_camera) { +////// - camera = p_camera; - set_spatial_node(camera); +MeshInstanceSpatialGizmoPlugin::MeshInstanceSpatialGizmoPlugin() { } -////// +bool MeshInstanceSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<MeshInstance>(p_spatial) != NULL && Object::cast_to<SoftBody>(p_spatial) == NULL; +} -bool MeshInstanceSpatialGizmo::can_draw() const { - return true; //mesh can always draw (even though nothing is displayed) +String MeshInstanceSpatialGizmoPlugin::get_name() const { + return "MeshInstance"; } -void MeshInstanceSpatialGizmo::redraw() { - clear(); +bool MeshInstanceSpatialGizmoPlugin::can_be_hidden() const { + return false; +} + +void MeshInstanceSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + MeshInstance *mesh = Object::cast_to<MeshInstance>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Ref<Mesh> m = mesh->get_mesh(); + if (!m.is_valid()) return; //none Ref<TriangleMesh> tm = m->generate_triangle_mesh(); if (tm.is_valid()) { - add_collision_triangles(tm); + p_gizmo->add_collision_triangles(tm); } } -MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance *p_mesh) { +///// +Sprite3DSpatialGizmoPlugin::Sprite3DSpatialGizmoPlugin() { +} - mesh = p_mesh; - set_spatial_node(p_mesh); +bool Sprite3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Sprite3D>(p_spatial) != NULL; } -///// +String Sprite3DSpatialGizmoPlugin::get_name() const { + return "Sprite3D"; +} -bool Sprite3DSpatialGizmo::can_draw() const { - return true; +bool Sprite3DSpatialGizmoPlugin::can_be_hidden() const { + return false; } -void Sprite3DSpatialGizmo::redraw() { - clear(); +void Sprite3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Sprite3D *sprite = Object::cast_to<Sprite3D>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Ref<TriangleMesh> tm = sprite->generate_triangle_mesh(); if (tm.is_valid()) { - add_collision_triangles(tm); + p_gizmo->add_collision_triangles(tm); } } -Sprite3DSpatialGizmo::Sprite3DSpatialGizmo(SpriteBase3D *p_sprite) { - - sprite = p_sprite; - set_spatial_node(p_sprite); -} - /// -void Position3DSpatialGizmo::redraw() { +Position3DSpatialGizmoPlugin::Position3DSpatialGizmoPlugin() { + pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + cursor_points = Vector<Vector3>(); - clear(); - add_mesh(SpatialEditorGizmos::singleton->pos3d_mesh); - Vector<Vector3> cursor_points; + PoolVector<Color> cursor_colors; float cs = 0.25; cursor_points.push_back(Vector3(+cs, 0, 0)); cursor_points.push_back(Vector3(-cs, 0, 0)); @@ -1382,51 +1415,65 @@ void Position3DSpatialGizmo::redraw() { cursor_points.push_back(Vector3(0, -cs, 0)); cursor_points.push_back(Vector3(0, 0, +cs)); cursor_points.push_back(Vector3(0, 0, -cs)); - add_collision_segments(cursor_points); + cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); + cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); + cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); + cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); + cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); + cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); + + Ref<SpatialMaterial> mat = memnew(SpatialMaterial); + mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); + mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); + mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); + mat->set_line_width(3); + Array d; + d.resize(VS::ARRAY_MAX); + d[Mesh::ARRAY_VERTEX] = cursor_points; + d[Mesh::ARRAY_COLOR] = cursor_colors; + pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); + pos3d_mesh->surface_set_material(0, mat); } -Position3DSpatialGizmo::Position3DSpatialGizmo(Position3D *p_p3d) { +bool Position3DSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Position3D>(p_spatial) != NULL; +} + +String Position3DSpatialGizmoPlugin::get_name() const { + return "Position3D"; +} + +void Position3DSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - p3d = p_p3d; - set_spatial_node(p3d); + p_gizmo->clear(); + p_gizmo->add_mesh(pos3d_mesh); + p_gizmo->add_collision_segments(cursor_points); } ///// -void SkeletonSpatialGizmo::redraw() { +SkeletonSpatialGizmoPlugin::SkeletonSpatialGizmoPlugin() { - clear(); + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4)); + create_material("skeleton_material", gizmo_color); +} - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/skeleton"); - Ref<Material> material = create_material("skeleton_material", gizmo_color); - SpatialMaterial *sm = Object::cast_to<SpatialMaterial>(material.ptr()); - - { // Reset - Color c(sm->get_albedo()); - c.a = 1; - sm->set_albedo(c); - } - if (sm) { - switch (SpatialEditor::get_singleton()->get_skeleton_visibility_state()) { - case 0: { - // Hidden - Color c(sm->get_albedo()); - c.a = 0; - sm->set_albedo(c); - sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - } break; - case 1: - // Visible - sm->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, false); - sm->set_render_priority(SpatialMaterial::RENDER_PRIORITY_MIN); - sm->set_flag(SpatialMaterial::FLAG_DISABLE_DEPTH_TEST, false); - break; - case 2: - // x-ray - sm->set_on_top_of_alpha(); - break; - } - } +bool SkeletonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Skeleton>(p_spatial) != NULL; +} + +String SkeletonSpatialGizmoPlugin::get_name() const { + return "Skeleton"; +} + +void SkeletonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Skeleton *skel = Object::cast_to<Skeleton>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Ref<Material> material = get_material("skeleton_material", p_gizmo); Ref<SurfaceTool> surface_tool(memnew(SurfaceTool)); @@ -1452,7 +1499,9 @@ void SkeletonSpatialGizmo::redraw() { Color bonecolor = Color(1.0, 0.4, 0.4, 0.3); Color rootcolor = Color(0.4, 1.0, 0.4, 0.1); - for (int i = 0; i < skel->get_bone_count(); i++) { + for (int i_bone = 0; i_bone < skel->get_bone_count(); i_bone++) { + + int i = skel->get_process_order(i_bone); int parent = skel->get_bone_parent(i); @@ -1604,24 +1653,28 @@ void SkeletonSpatialGizmo::redraw() { } Ref<ArrayMesh> m = surface_tool->commit(); - add_mesh(m, false, skel->get_skeleton()); + p_gizmo->add_mesh(m, false, skel->get_skeleton()); } -SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton *p_skel) { +//// + +PhysicalBoneSpatialGizmoPlugin::PhysicalBoneSpatialGizmoPlugin() { + create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1))); +} - skel = p_skel; - set_spatial_node(p_skel); +bool PhysicalBoneSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<PhysicalBone>(p_spatial) != NULL; } -PhysicalBoneSpatialGizmo::PhysicalBoneSpatialGizmo(PhysicalBone *p_pb) : - EditorSpatialGizmo(), - physical_bone(p_pb) { - set_spatial_node(p_pb); +String PhysicalBoneSpatialGizmoPlugin::get_name() const { + return "PhysicalBones"; } -void PhysicalBoneSpatialGizmo::redraw() { +void PhysicalBoneSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + p_gizmo->clear(); + + PhysicalBone *physical_bone = Object::cast_to<PhysicalBone>(p_gizmo->get_spatial_node()); if (!physical_bone) return; @@ -1635,26 +1688,25 @@ void PhysicalBoneSpatialGizmo::redraw() { switch (physical_bone->get_joint_type()) { case PhysicalBone::JOINT_TYPE_PIN: { - PinJointSpatialGizmo::CreateGizmo(physical_bone->get_joint_offset(), points); + JointSpatialGizmoPlugin::CreatePinJointGizmo(physical_bone->get_joint_offset(), points); } break; case PhysicalBone::JOINT_TYPE_CONE: { const PhysicalBone::ConeJointData *cjd(static_cast<const PhysicalBone::ConeJointData *>(physical_bone->get_joint_data())); - ConeTwistJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateConeTwistJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), pb ? pb->get_global_transform() : Transform(), pbp ? pbp->get_global_transform() : Transform(), cjd->swing_span, cjd->twist_span, - points, pb ? &points : NULL, pbp ? &points : NULL); } break; case PhysicalBone::JOINT_TYPE_HINGE: { const PhysicalBone::HingeJointData *hjd(static_cast<const PhysicalBone::HingeJointData *>(physical_bone->get_joint_data())); - HingeJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateHingeJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), pb ? pb->get_global_transform() : Transform(), @@ -1669,7 +1721,7 @@ void PhysicalBoneSpatialGizmo::redraw() { case PhysicalBone::JOINT_TYPE_SLIDER: { const PhysicalBone::SliderJointData *sjd(static_cast<const PhysicalBone::SliderJointData *>(physical_bone->get_joint_data())); - SliderJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateSliderJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), pb ? pb->get_global_transform() : Transform(), @@ -1685,7 +1737,7 @@ void PhysicalBoneSpatialGizmo::redraw() { case PhysicalBone::JOINT_TYPE_6DOF: { const PhysicalBone::SixDOFJointData *sdofjd(static_cast<const PhysicalBone::SixDOFJointData *>(physical_bone->get_joint_data())); - Generic6DOFJointSpatialGizmo::CreateGizmo( + JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo( physical_bone->get_joint_offset(), physical_bone->get_global_transform() * physical_bone->get_joint_offset(), @@ -1721,14 +1773,15 @@ void PhysicalBoneSpatialGizmo::redraw() { return; } - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); + Ref<Material> material = get_material("joint_material", p_gizmo); - add_collision_segments(points); - add_lines(points, material); + p_gizmo->add_collision_segments(points); + p_gizmo->add_lines(points, material); } // FIXME: Kept as reference for reimplementation in 3.1+ #if 0 + void RoomSpatialGizmo::redraw() { clear(); @@ -1745,41 +1798,41 @@ void RoomSpatialGizmo::redraw() { for (int i = 0; i < fc; i++) { - Vector3 fn = r[i].get_plane().normal; + Vector3 fn = r[i].get_plane().normal; - for (int j = 0; j < 3; j++) { + for (int j = 0; j < 3; j++) { - _EdgeKey ek; - ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); - if (ek.from < ek.to) - SWAP(ek.from, ek.to); + _EdgeKey ek; + ek.from = r[i].vertex[j].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + ek.to = r[i].vertex[(j + 1) % 3].snapped(Vector3(CMP_EPSILON, CMP_EPSILON, CMP_EPSILON)); + if (ek.from < ek.to) + SWAP(ek.from, ek.to); - Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek); + Map<_EdgeKey, Vector3>::Element *E = edge_map.find(ek); - if (E) { + if (E) { - if (E->get().dot(fn) > 0.9) { + if (E->get().dot(fn) > 0.9) { - E->get() = Vector3(); - } + E->get() = Vector3(); + } - } else { + } else { - edge_map[ek] = fn; - } + edge_map[ek] = fn; + } + } } - } for (Map<_EdgeKey, Vector3>::Element *E = edge_map.front(); E; E = E->next()) { - if (E->get() != Vector3()) { - lines.push_back(E->key().from); - lines.push_back(E->key().to); + if (E->get() != Vector3()) { + lines.push_back(E->key().from); + lines.push_back(E->key().to); + } } - } - add_lines(lines, SpatialEditorGizmos::singleton->room_material); + add_lines(lines, EditorSpatialGizmos::singleton->room_material); add_collision_segments(lines); } @@ -1797,31 +1850,31 @@ void PortalSpatialGizmo::redraw() { Vector<Point2> points = portal->get_shape(); if (points.size() == 0) { - return; - } + return; + } Vector<Vector3> lines; Vector3 center; for (int i = 0; i < points.size(); i++) { - Vector3 f; - f.x = points[i].x; - f.y = points[i].y; - Vector3 fn; - fn.x = points[(i + 1) % points.size()].x; - fn.y = points[(i + 1) % points.size()].y; - center += f; + Vector3 f; + f.x = points[i].x; + f.y = points[i].y; + Vector3 fn; + fn.x = points[(i + 1) % points.size()].x; + fn.y = points[(i + 1) % points.size()].y; + center += f; - lines.push_back(f); - lines.push_back(fn); - } + lines.push_back(f); + lines.push_back(fn); + } center /= points.size(); lines.push_back(center); lines.push_back(center + Vector3(0, 0, 1)); - add_lines(lines, SpatialEditorGizmos::singleton->portal_material); + add_lines(lines, EditorSpatialGizmos::singleton->portal_material); add_collision_segments(lines); } @@ -1834,33 +1887,58 @@ PortalSpatialGizmo::PortalSpatialGizmo(Portal *p_portal) { #endif ///// -void RayCastSpatialGizmo::redraw() { +RayCastSpatialGizmoPlugin::RayCastSpatialGizmoPlugin() { - clear(); + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); +} + +bool RayCastSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<RayCast>(p_spatial) != NULL; +} + +String RayCastSpatialGizmoPlugin::get_name() const { + return "RayCast"; +} + +void RayCastSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + RayCast *raycast = Object::cast_to<RayCast>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector3> lines; lines.push_back(Vector3()); lines.push_back(raycast->get_cast_to()); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<SpatialMaterial> material = get_material("shape_material", p_gizmo); - add_lines(lines, material); - add_collision_segments(lines); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); } -RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast *p_raycast) { +///// + +VehicleWheelSpatialGizmoPlugin::VehicleWheelSpatialGizmoPlugin() { - set_spatial_node(p_raycast); - raycast = p_raycast; + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); } -///// +bool VehicleWheelSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<VehicleWheel>(p_spatial) != NULL; +} -void VehicleWheelSpatialGizmo::redraw() { +String VehicleWheelSpatialGizmoPlugin::get_name() const { + return "VehicleWheel"; +} - clear(); +void VehicleWheelSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + VehicleWheel *car_wheel = Object::cast_to<VehicleWheel>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector3> points; @@ -1904,23 +1982,36 @@ void VehicleWheelSpatialGizmo::redraw() { points.push_back(Vector3(0, -r, r * 2)); points.push_back(Vector3(-r * 2 * 0.2, -r, r * 2 * 0.8)); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<Material> material = get_material("shape_material", p_gizmo); - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); } -VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel) { +/////////// - set_spatial_node(p_car_wheel); - car_wheel = p_car_wheel; +SoftBodySpatialGizmoPlugin::SoftBodySpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); + create_handle_material("handles"); } -/////////// +bool SoftBodySpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<SoftBody>(p_spatial) != NULL; +} -void SoftBodySpatialGizmo::redraw() { - clear(); +String SoftBodySpatialGizmoPlugin::get_name() const { + return "SoftBody"; +} + +bool SoftBodySpatialGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +void SoftBodySpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); if (!soft_body || soft_body->get_mesh().is_null()) { return; @@ -1936,84 +2027,840 @@ void SoftBodySpatialGizmo::redraw() { return; } + Ref<TriangleMesh> tm = soft_body->get_mesh()->generate_triangle_mesh(); + Vector<Vector3> points; soft_body->get_mesh()->generate_debug_mesh_indices(points); - soft_body->get_mesh()->clear_cache(); - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<Material> material = get_material("shape_material", p_gizmo); - add_lines(lines, material); - add_collision_segments(lines); - add_handles(points); -} - -bool SoftBodySpatialGizmo::intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle, bool p_sec_first) { - return EditorSpatialGizmo::intersect_ray(p_camera, p_point, r_pos, r_normal, r_gizmo_handle, p_sec_first); - - /* Perform a shape cast but doesn't work with softbody - PhysicsDirectSpaceState *space_state = PhysicsServer::get_singleton()->space_get_direct_state(SceneTree::get_singleton()->get_root()->get_world()->get_space()); - if (!physics_sphere_shape.is_valid()) { - physics_sphere_shape = PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_SPHERE); - real_t radius = 0.02; - PhysicsServer::get_singleton()->shape_set_data(physics_sphere_shape, radius); - } - - Vector3 sphere_motion(p_camera->project_ray_normal(p_point)); - real_t closest_safe; - real_t closest_unsafe; - PhysicsDirectSpaceState::ShapeRestInfo result; - bool collided = space_state->cast_motion( - physics_sphere_shape, - p_camera->get_transform(), - sphere_motion * Vector3(1000, 1000, 1000), - 0.f, - closest_safe, - closest_unsafe, - Set<RID>(), - 0xFFFFFFFF, - 0xFFFFFFFF, - &result); - - if (collided) { - - if (result.collider_id == soft_body->get_instance_id()) { - print_line("Collided"); - } else { - print_line("Collided but with wrong object: " + itos(result.collider_id)); - } - } else { - print_line("Not collided, motion: x: " + rtos(sphere_motion[0]) + " y: " + rtos(sphere_motion[1]) + " z: " + rtos(sphere_motion[2])); - } - return false; - */ + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(points, get_material("handles")); + p_gizmo->add_collision_triangles(tm); +} + +String SoftBodySpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + return "SoftBody pin point"; +} + +Variant SoftBodySpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); + return Variant(soft_body->is_point_pinned(p_idx)); } -void SoftBodySpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void SoftBodySpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); soft_body->pin_point_toggle(p_idx); - redraw(); } -bool SoftBodySpatialGizmo::is_gizmo_handle_highlighted(int idx) const { +bool SoftBodySpatialGizmoPlugin::is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const { + SoftBody *soft_body = Object::cast_to<SoftBody>(p_gizmo->get_spatial_node()); return soft_body->is_point_pinned(idx); } -SoftBodySpatialGizmo::SoftBodySpatialGizmo(SoftBody *p_soft_physics_body) : - EditorSpatialGizmo(), - soft_body(p_soft_physics_body) { - set_spatial_node(p_soft_physics_body); +/////////// + +VisibilityNotifierGizmoPlugin::VisibilityNotifierGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); + create_material("visibility_notifier_material", gizmo_color); + gizmo_color.a = 0.1; + create_material("visibility_notifier_solid_material", gizmo_color); + create_handle_material("handles"); } -SoftBodySpatialGizmo::~SoftBodySpatialGizmo() { - //if (!physics_sphere_shape.is_valid()) { - // PhysicsServer::get_singleton()->free(physics_sphere_shape); - //} +bool VisibilityNotifierGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<VisibilityNotifier>(p_spatial) != NULL; } -/////////// +String VisibilityNotifierGizmoPlugin::get_name() const { + return "VisibilityNotifier"; +} + +String VisibilityNotifierGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Size X"; + case 1: return "Size Y"; + case 2: return "Size Z"; + case 3: return "Pos X"; + case 4: return "Pos Y"; + case 5: return "Pos Z"; + } + + return ""; +} + +Variant VisibilityNotifierGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + return notifier->get_aabb(); +} +void VisibilityNotifierGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + + Transform gt = notifier->get_global_transform(); + + Transform gi = gt.affine_inverse(); + + bool move = p_idx >= 3; + p_idx = p_idx % 3; + + AABB aabb = notifier->get_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.position + aabb.size * 0.5; + + Vector3 axis; + axis[p_idx] = 1.0; + + if (move) { + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx]; + + aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; + notifier->set_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx] - ofs[p_idx]; + if (d < 0.001) + d = 0.001; + //resize + aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; + aabb.size[p_idx] = d * 2; + notifier->set_aabb(aabb); + } +} + +void VisibilityNotifierGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + + if (p_cancel) { + notifier->set_aabb(p_restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Notifier AABB")); + ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); + ur->add_undo_method(notifier, "set_aabb", p_restore); + ur->commit_action(); +} + +void VisibilityNotifierGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + VisibilityNotifier *notifier = Object::cast_to<VisibilityNotifier>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector<Vector3> lines; + AABB aabb = notifier->get_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.position + aabb.size * 0.5; + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + Ref<Material> material = get_material("visibility_notifier_material", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); + } + + p_gizmo->add_handles(handles, get_material("handles")); +} + +//// + +ParticlesGizmoPlugin::ParticlesGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); + create_material("particles_material", gizmo_color); + gizmo_color.a = 0.1; + create_material("particles_solid_material", gizmo_color); + create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons")); + create_handle_material("handles"); +} + +bool ParticlesGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Particles>(p_spatial) != NULL; +} + +String ParticlesGizmoPlugin::get_name() const { + return "Particles"; +} + +bool ParticlesGizmoPlugin::is_selectable_when_hidden() const { + return true; +} + +String ParticlesGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Size X"; + case 1: return "Size Y"; + case 2: return "Size Z"; + case 3: return "Pos X"; + case 4: return "Pos Y"; + case 5: return "Pos Z"; + } + + return ""; +} +Variant ParticlesGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + return particles->get_visibility_aabb(); +} +void ParticlesGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + + Transform gt = particles->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + bool move = p_idx >= 3; + p_idx = p_idx % 3; + + AABB aabb = particles->get_visibility_aabb(); + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; + + Vector3 ofs = aabb.position + aabb.size * 0.5; + + Vector3 axis; + axis[p_idx] = 1.0; + + if (move) { + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx]; + + aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; + particles->set_visibility_aabb(aabb); + + } else { + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); + + float d = ra[p_idx] - ofs[p_idx]; + if (d < 0.001) + d = 0.001; + //resize + aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; + aabb.size[p_idx] = d * 2; + particles->set_visibility_aabb(aabb); + } +} + +void ParticlesGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + + if (p_cancel) { + particles->set_visibility_aabb(p_restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Particles AABB")); + ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb()); + ur->add_undo_method(particles, "set_custom_aabb", p_restore); + ur->commit_action(); +} + +void ParticlesGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + Particles *particles = Object::cast_to<Particles>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector<Vector3> lines; + AABB aabb = particles->get_visibility_aabb(); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; + ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; + handles.push_back(ax); + } + + Vector3 center = aabb.position + aabb.size * 0.5; + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = 1.0; + handles.push_back(center + ax); + lines.push_back(center); + lines.push_back(center + ax); + } + + Ref<Material> material = get_material("particles_material", p_gizmo); + Ref<Material> icon = get_material("particles_icon", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); + } + + p_gizmo->add_handles(handles, get_material("handles")); + p_gizmo->add_unscaled_billboard(icon, 0.05); +} +//// + +ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); + + create_material("reflection_probe_material", gizmo_color); + + gizmo_color.a = 0.5; + create_material("reflection_internal_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("reflection_probe_solid_material", gizmo_color); + + create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons")); + create_handle_material("handles"); +} + +bool ReflectionProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<ReflectionProbe>(p_spatial) != NULL; +} + +String ReflectionProbeGizmoPlugin::get_name() const { + return "ReflectionProbe"; +} + +String ReflectionProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + case 3: return "Origin X"; + case 4: return "Origin Y"; + case 5: return "Origin Z"; + } + + return ""; +} +Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + return AABB(probe->get_extents(), probe->get_origin_offset()); +} +void ReflectionProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + Transform gt = probe->get_global_transform(); + + Transform gi = gt.affine_inverse(); + + if (p_idx < 3) { + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + probe->set_extents(extents); + } else { + + p_idx -= 3; + + Vector3 origin = probe->get_origin_offset(); + origin[p_idx] = 0; + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + d += 0.25; + + origin[p_idx] = d; + probe->set_origin_offset(origin); + } +} + +void ReflectionProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + + AABB restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore.position); + probe->set_origin_offset(restore.size); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe, "set_extents", probe->get_extents()); + ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); + ur->add_undo_method(probe, "set_extents", restore.position); + ur->add_undo_method(probe, "set_origin_offset", restore.size); + ur->commit_action(); +} + +void ReflectionProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Vector<Vector3> lines; + Vector<Vector3> internal_lines; + Vector3 extents = probe->get_extents(); + + AABB aabb; + aabb.position = -extents; + aabb.size = extents * 2; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + for (int i = 0; i < 8; i++) { + Vector3 ep = aabb.get_endpoint(i); + internal_lines.push_back(probe->get_origin_offset()); + internal_lines.push_back(ep); + } + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + for (int i = 0; i < 3; i++) { + + Vector3 orig_handle = probe->get_origin_offset(); + orig_handle[i] -= 0.25; + lines.push_back(orig_handle); + handles.push_back(orig_handle); + + orig_handle[i] += 0.5; + lines.push_back(orig_handle); + } + + Ref<Material> material = get_material("reflection_probe_material", p_gizmo); + Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo); + Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo); + + p_gizmo->add_lines(lines, material); + p_gizmo->add_lines(internal_lines, material_internal); + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, probe->get_extents() * 2.0); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, get_material("handles")); +} + +GIProbeGizmoPlugin::GIProbeGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); + + create_material("gi_probe_material", gizmo_color); + + gizmo_color.a = 0.5; + create_material("gi_probe_internal_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("gi_probe_solid_material", gizmo_color); + + create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons")); + create_handle_material("handles"); +} + +bool GIProbeGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<GIProbe>(p_spatial) != NULL; +} + +String GIProbeGizmoPlugin::get_name() const { + return "GIProbe"; +} + +String GIProbeGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + } + + return ""; +} +Variant GIProbeGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + return probe->get_extents(); +} +void GIProbeGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + + Transform gt = probe->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + probe->set_extents(extents); +} + +void GIProbeGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + + Vector3 restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe, "set_extents", probe->get_extents()); + ur->add_undo_method(probe, "set_extents", restore); + ur->commit_action(); +} + +void GIProbeGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); + + Ref<Material> material = get_material("gi_probe_material", p_gizmo); + Ref<Material> icon = get_material("gi_probe_icon", p_gizmo); + Ref<Material> material_internal = get_material("gi_probe_internal_material", p_gizmo); + + p_gizmo->clear(); + + Vector<Vector3> lines; + Vector3 extents = probe->get_extents(); + + static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 }; + + AABB aabb = AABB(-extents, extents * 2); + int subdiv = subdivs[probe->get_subdiv()]; + float cell_size = aabb.get_longest_axis_size() / subdiv; + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + lines.clear(); + + for (int i = 1; i < subdiv; i++) { + + for (int j = 0; j < 3; j++) { + + if (cell_size * i > aabb.size[j]) { + continue; + } + + Vector2 dir; + dir[j] = 1.0; + Vector2 ta, tb; + int j_n1 = (j + 1) % 3; + int j_n2 = (j + 2) % 3; + ta[j_n1] = 1.0; + tb[j_n2] = 1.0; + + for (int k = 0; k < 4; k++) { + + Vector3 from = aabb.position, to = aabb.position; + from[j] += cell_size * i; + to[j] += cell_size * i; + + if (k & 1) { + to[j_n1] += aabb.size[j_n1]; + } else { + + to[j_n2] += aabb.size[j_n2]; + } + + if (k & 2) { + from[j_n1] += aabb.size[j_n1]; + from[j_n2] += aabb.size[j_n2]; + } + + lines.push_back(from); + lines.push_back(to); + } + } + } + + p_gizmo->add_lines(lines, material_internal); + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + if (p_gizmo->is_selected()) { + Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo); + p_gizmo->add_solid_box(solid_material, aabb.get_size()); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); +} + +//// + +BakedIndirectLightGizmoPlugin::BakedIndirectLightGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1)); + + create_material("baked_indirect_light_material", gizmo_color); + + gizmo_color.a = 0.1; + create_material("baked_indirect_light_internal_material", gizmo_color); + + create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons")); + create_handle_material("handles"); +} + +String BakedIndirectLightGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + switch (p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + } + + return ""; +} +Variant BakedIndirectLightGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + return baker->get_extents(); +} +void BakedIndirectLightGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + + Transform gt = baker->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + Vector3 extents = baker->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; + + Vector3 axis; + axis[p_idx] = 1.0; + + Vector3 ra, rb; + Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); + float d = ra[p_idx]; + if (d < 0.001) + d = 0.001; + + extents[p_idx] = d; + baker->set_extents(extents); +} + +void BakedIndirectLightGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + + Vector3 restore = p_restore; + + if (p_cancel) { + baker->set_extents(restore); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(baker, "set_extents", baker->get_extents()); + ur->add_undo_method(baker, "set_extents", restore); + ur->commit_action(); +} + +bool BakedIndirectLightGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<BakedLightmap>(p_spatial) != NULL; +} + +String BakedIndirectLightGizmoPlugin::get_name() const { + return "BakedLightmap"; +} + +void BakedIndirectLightGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); + + Ref<Material> material = get_material("baked_indirect_light_material", p_gizmo); + Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo); + Ref<Material> material_internal = get_material("baked_indirect_light_internal_material", p_gizmo); + + p_gizmo->clear(); + + Vector<Vector3> lines; + Vector3 extents = baker->get_extents(); + + AABB aabb = AABB(-extents, extents * 2); + + for (int i = 0; i < 12; i++) { + Vector3 a, b; + aabb.get_edge(i, a, b); + lines.push_back(a); + lines.push_back(b); + } + + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + + Vector<Vector3> handles; + + for (int i = 0; i < 3; i++) { + + Vector3 ax; + ax[i] = aabb.position[i] + aabb.size[i]; + handles.push_back(ax); + } + + if (p_gizmo->is_selected()) { + p_gizmo->add_solid_box(material_internal, aabb.get_size()); + } + + p_gizmo->add_unscaled_billboard(icon, 0.05); + p_gizmo->add_handles(handles, get_material("handles")); +} + +//// + +CollisionShapeSpatialGizmoPlugin::CollisionShapeSpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); + create_handle_material("handles"); +} + +bool CollisionShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<CollisionShape>(p_spatial) != NULL; +} + +String CollisionShapeSpatialGizmoPlugin::get_name() const { + return "CollisionShape"; +} -String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { +String CollisionShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + const CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); Ref<Shape> s = cs->get_shape(); if (s.is_null()) @@ -2046,7 +2893,10 @@ String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const { return ""; } -Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const { + +Variant CollisionShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); Ref<Shape> s = cs->get_shape(); if (s.is_null()) @@ -2084,7 +2934,10 @@ Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const { return Variant(); } -void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void CollisionShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); + Ref<Shape> s = cs->get_shape(); if (s.is_null()) return; @@ -2175,7 +3028,10 @@ void CollisionShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const P cs->set_height(d * 2.0); } } -void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void CollisionShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); + Ref<Shape> s = cs->get_shape(); if (s.is_null()) return; @@ -2252,7 +3108,11 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius()); ur->add_undo_method(ss.ptr(), "set_radius", p_restore); } else { - ur->create_action(TTR("Change Cylinder Shape Height")); + ur->create_action( + /// + + //////// + TTR("Change Cylinder Shape Height")); ur->add_do_method(ss.ptr(), "set_height", ss->get_height()); ur->add_undo_method(ss.ptr(), "set_height", p_restore); } @@ -2275,16 +3135,18 @@ void CollisionShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_resto ur->commit_action(); } } -void CollisionShapeSpatialGizmo::redraw() { +void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { - clear(); + CollisionShape *cs = Object::cast_to<CollisionShape>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Ref<Shape> s = cs->get_shape(); if (s.is_null()) return; - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); + Ref<Material> material = get_material("shape_material", p_gizmo); + Ref<Material> handles_material = get_material("handles"); if (Object::cast_to<SphereShape>(*s)) { @@ -2325,11 +3187,11 @@ void CollisionShapeSpatialGizmo::redraw() { collision_segments.push_back(Vector3(b.x, b.y, 0)); } - add_lines(points, material); - add_collision_segments(collision_segments); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(collision_segments); Vector<Vector3> handles; handles.push_back(Vector3(r, 0, 0)); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<BoxShape>(*s)) { @@ -2356,9 +3218,9 @@ void CollisionShapeSpatialGizmo::redraw() { handles.push_back(ax); } - add_lines(lines, material); - add_collision_segments(lines); - add_handles(handles); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CapsuleShape>(*s)) { @@ -2397,7 +3259,7 @@ void CollisionShapeSpatialGizmo::redraw() { points.push_back(Vector3(b.y, 0, b.x) + dud); } - add_lines(points, material); + p_gizmo->add_lines(points, material); Vector<Vector3> collision_segments; @@ -2428,12 +3290,12 @@ void CollisionShapeSpatialGizmo::redraw() { collision_segments.push_back(Vector3(b.y, 0, b.x) + dud); } - add_collision_segments(collision_segments); + p_gizmo->add_collision_segments(collision_segments); Vector<Vector3> handles; handles.push_back(Vector3(cs->get_radius(), 0, 0)); handles.push_back(Vector3(0, 0, cs->get_height() * 0.5 + cs->get_radius())); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CylinderShape>(*s)) { @@ -2465,7 +3327,7 @@ void CollisionShapeSpatialGizmo::redraw() { } } - add_lines(points, material); + p_gizmo->add_lines(points, material); Vector<Vector3> collision_segments; @@ -2489,12 +3351,12 @@ void CollisionShapeSpatialGizmo::redraw() { } } - add_collision_segments(collision_segments); + p_gizmo->add_collision_segments(collision_segments); Vector<Vector3> handles; handles.push_back(Vector3(cs->get_radius(), 0, 0)); handles.push_back(Vector3(0, cs->get_height() * 0.5, 0)); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<PlaneShape>(*s)) { @@ -2524,8 +3386,8 @@ void CollisionShapeSpatialGizmo::redraw() { points.push_back(p.normal * p.d); points.push_back(p.normal * p.d + p.normal * 3); - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); } if (Object::cast_to<ConvexPolygonShape>(*s)) { @@ -2546,8 +3408,8 @@ void CollisionShapeSpatialGizmo::redraw() { points.write[i * 2 + 1] = md.vertices[md.edges[i].b]; } - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); } } } @@ -2559,24 +3421,34 @@ void CollisionShapeSpatialGizmo::redraw() { Vector<Vector3> points; points.push_back(Vector3()); points.push_back(Vector3(0, 0, rs->get_length())); - add_lines(points, material); - add_collision_segments(points); + p_gizmo->add_lines(points, material); + p_gizmo->add_collision_segments(points); Vector<Vector3> handles; handles.push_back(Vector3(0, 0, rs->get_length())); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } } -CollisionShapeSpatialGizmo::CollisionShapeSpatialGizmo(CollisionShape *p_cs) { - cs = p_cs; - set_spatial_node(p_cs); +///// + +CollisionPolygonSpatialGizmoPlugin::CollisionPolygonSpatialGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); + create_material("shape_material", gizmo_color); } -///// +bool CollisionPolygonSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<CollisionPolygon>(p_spatial) != NULL; +} -void CollisionPolygonSpatialGizmo::redraw() { +String CollisionPolygonSpatialGizmoPlugin::get_name() const { + return "CollisionPolygon"; +} - clear(); +void CollisionPolygonSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + CollisionPolygon *polygon = Object::cast_to<CollisionPolygon>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); Vector<Vector2> points = polygon->get_polygon(); float depth = polygon->get_depth() * 0.5; @@ -2593,695 +3465,39 @@ void CollisionPolygonSpatialGizmo::redraw() { lines.push_back(Vector3(points[i].x, points[i].y, -depth)); } - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape"); - Ref<Material> material = create_material("shape_material", gizmo_color); - - add_lines(lines, material); - add_collision_segments(lines); -} - -CollisionPolygonSpatialGizmo::CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon) { - - set_spatial_node(p_polygon); - polygon = p_polygon; -} -/// - -String VisibilityNotifierGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "X"; - case 1: return "Y"; - case 2: return "Z"; - } - - return ""; -} -Variant VisibilityNotifierGizmo::get_handle_value(int p_idx) const { - - return notifier->get_aabb(); -} -void VisibilityNotifierGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = notifier->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - AABB aabb = notifier->get_aabb(); - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - Vector3 ofs = aabb.position + aabb.size * 0.5; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; - - aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; - aabb.size[p_idx] = d * 2; - notifier->set_aabb(aabb); -} - -void VisibilityNotifierGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - if (p_cancel) { - notifier->set_aabb(p_restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Notifier Extents")); - ur->add_do_method(notifier, "set_aabb", notifier->get_aabb()); - ur->add_undo_method(notifier, "set_aabb", p_restore); - ur->commit_action(); -} - -void VisibilityNotifierGizmo::redraw() { - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/visibility_notifier"); - Ref<Material> material = create_material("visibility_notifier_material", gizmo_color); - - clear(); - - Vector<Vector3> lines; - AABB aabb = notifier->get_aabb(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - add_lines(lines, material); - //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); - add_collision_segments(lines); - add_handles(handles); -} -VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier *p_notifier) { - - notifier = p_notifier; - set_spatial_node(p_notifier); -} - -//////// - -/// - -String ParticlesGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Size X"; - case 1: return "Size Y"; - case 2: return "Size Z"; - case 3: return "Pos X"; - case 4: return "Pos Y"; - case 5: return "Pos Z"; - } - - return ""; -} -Variant ParticlesGizmo::get_handle_value(int p_idx) const { - - return particles->get_visibility_aabb(); -} -void ParticlesGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = particles->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - bool move = p_idx >= 3; - p_idx = p_idx % 3; - - AABB aabb = particles->get_visibility_aabb(); - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; - - Vector3 ofs = aabb.position + aabb.size * 0.5; - - Vector3 axis; - axis[p_idx] = 1.0; - - if (move) { - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_idx]; - - aabb.position[p_idx] = d - 1.0 - aabb.size[p_idx] * 0.5; - particles->set_visibility_aabb(aabb); - - } else { - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb); - - float d = ra[p_idx] - ofs[p_idx]; - if (d < 0.001) - d = 0.001; - //resize - aabb.position[p_idx] = (aabb.position[p_idx] + aabb.size[p_idx] * 0.5) - d; - aabb.size[p_idx] = d * 2; - particles->set_visibility_aabb(aabb); - } -} - -void ParticlesGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - if (p_cancel) { - particles->set_visibility_aabb(p_restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Particles AABB")); - ur->add_do_method(particles, "set_custom_aabb", particles->get_visibility_aabb()); - ur->add_undo_method(particles, "set_custom_aabb", p_restore); - ur->commit_action(); -} - -void ParticlesGizmo::redraw() { - - clear(); - - Vector<Vector3> lines; - AABB aabb = particles->get_visibility_aabb(); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5; - ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5; - handles.push_back(ax); - } - - Vector3 center = aabb.position + aabb.size * 0.5; - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = 1.0; - handles.push_back(center + ax); - lines.push_back(center); - lines.push_back(center + ax); - } - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/particles"); - Ref<Material> material = create_material("particles_material", gizmo_color); - Ref<Material> icon = create_icon_material("particles_icon", SpatialEditor::get_singleton()->get_icon("GizmoParticles", "EditorIcons")); - - add_lines(lines, material); - add_collision_segments(lines); - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("particles_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size(), aabb.get_position() + aabb.get_size() / 2.0); - } - - //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); + Ref<Material> material = get_material("shape_material", p_gizmo); - add_handles(handles); - add_unscaled_billboard(icon, 0.05); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); } -ParticlesGizmo::ParticlesGizmo(Particles *p_particles) { - particles = p_particles; - set_spatial_node(p_particles); -} - -//////// - -/// - -String ReflectionProbeGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Extents X"; - case 1: return "Extents Y"; - case 2: return "Extents Z"; - case 3: return "Origin X"; - case 4: return "Origin Y"; - case 5: return "Origin Z"; - } - - return ""; -} -Variant ReflectionProbeGizmo::get_handle_value(int p_idx) const { - - return AABB(probe->get_extents(), probe->get_origin_offset()); -} -void ReflectionProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = probe->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - if (p_idx < 3) { - Vector3 extents = probe->get_extents(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; - - extents[p_idx] = d; - probe->set_extents(extents); - } else { - - p_idx -= 3; - - Vector3 origin = probe->get_origin_offset(); - origin[p_idx] = 0; - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(origin - axis * 16384, origin + axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - d += 0.25; - - origin[p_idx] = d; - probe->set_origin_offset(origin); - } -} - -void ReflectionProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - AABB restore = p_restore; - - if (p_cancel) { - probe->set_extents(restore.position); - probe->set_origin_offset(restore.size); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Probe Extents")); - ur->add_do_method(probe, "set_extents", probe->get_extents()); - ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset()); - ur->add_undo_method(probe, "set_extents", restore.position); - ur->add_undo_method(probe, "set_origin_offset", restore.size); - ur->commit_action(); -} - -void ReflectionProbeGizmo::redraw() { - - clear(); - - Vector<Vector3> lines; - Vector<Vector3> internal_lines; - Vector3 extents = probe->get_extents(); - - AABB aabb; - aabb.position = -extents; - aabb.size = extents * 2; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - for (int i = 0; i < 8; i++) { - Vector3 ep = aabb.get_endpoint(i); - internal_lines.push_back(probe->get_origin_offset()); - internal_lines.push_back(ep); - } - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - for (int i = 0; i < 3; i++) { - - Vector3 orig_handle = probe->get_origin_offset(); - orig_handle[i] -= 0.25; - lines.push_back(orig_handle); - handles.push_back(orig_handle); - - orig_handle[i] += 0.5; - lines.push_back(orig_handle); - } - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/reflection_probe"); - Ref<Material> material = create_material("reflection_probe_material", gizmo_color); - Ref<Material> icon = create_icon_material("reflection_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoReflectionProbe", "EditorIcons")); - - Color gizmo_color_internal = gizmo_color; - gizmo_color_internal.a = 0.5; - Ref<Material> material_internal = create_material("reflection_internal_material", gizmo_color_internal); - - add_lines(lines, material); - add_lines(internal_lines, material_internal); - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("reflection_probe_solid_material", gizmo_color); - add_solid_box(solid_material, probe->get_extents() * 2.0); - } - - //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); - add_unscaled_billboard(icon, 0.05); - add_collision_segments(lines); - add_handles(handles); -} -ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe *p_probe) { - - probe = p_probe; - set_spatial_node(p_probe); -} - -//////// - -/// - -String GIProbeGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Extents X"; - case 1: return "Extents Y"; - case 2: return "Extents Z"; - } - - return ""; -} -Variant GIProbeGizmo::get_handle_value(int p_idx) const { - - return probe->get_extents(); -} -void GIProbeGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = probe->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - Vector3 extents = probe->get_extents(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; - - extents[p_idx] = d; - probe->set_extents(extents); -} - -void GIProbeGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - Vector3 restore = p_restore; - - if (p_cancel) { - probe->set_extents(restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Probe Extents")); - ur->add_do_method(probe, "set_extents", probe->get_extents()); - ur->add_undo_method(probe, "set_extents", restore); - ur->commit_action(); -} - -void GIProbeGizmo::redraw() { - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/gi_probe"); - Ref<Material> material = create_material("gi_probe_material", gizmo_color); - Ref<Material> icon = create_icon_material("gi_probe_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons")); - Color gizmo_color_internal = gizmo_color; - gizmo_color_internal.a = 0.1; - Ref<Material> material_internal = create_material("gi_probe_internal_material", gizmo_color_internal); - - clear(); - - Vector<Vector3> lines; - Vector3 extents = probe->get_extents(); - - static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 }; - - AABB aabb = AABB(-extents, extents * 2); - int subdiv = subdivs[probe->get_subdiv()]; - float cell_size = aabb.get_longest_axis_size() / subdiv; - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - add_lines(lines, material); - add_collision_segments(lines); - - lines.clear(); - - for (int i = 1; i < subdiv; i++) { - - for (int j = 0; j < 3; j++) { - - if (cell_size * i > aabb.size[j]) { - continue; - } - - Vector2 dir; - dir[j] = 1.0; - Vector2 ta, tb; - int j_n1 = (j + 1) % 3; - int j_n2 = (j + 2) % 3; - ta[j_n1] = 1.0; - tb[j_n2] = 1.0; - - for (int k = 0; k < 4; k++) { - - Vector3 from = aabb.position, to = aabb.position; - from[j] += cell_size * i; - to[j] += cell_size * i; - - if (k & 1) { - to[j_n1] += aabb.size[j_n1]; - } else { - - to[j_n2] += aabb.size[j_n2]; - } - - if (k & 2) { - from[j_n1] += aabb.size[j_n1]; - from[j_n2] += aabb.size[j_n2]; - } - - lines.push_back(from); - lines.push_back(to); - } - } - } - - add_lines(lines, material_internal); - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("gi_probe_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size()); - } - - add_unscaled_billboard(icon, 0.05); - add_handles(handles); -} -GIProbeGizmo::GIProbeGizmo(GIProbe *p_probe) { - - probe = p_probe; - set_spatial_node(p_probe); -} - -//////// -//////// - -/// - -String BakedIndirectLightGizmo::get_handle_name(int p_idx) const { - - switch (p_idx) { - case 0: return "Extents X"; - case 1: return "Extents Y"; - case 2: return "Extents Z"; - } - - return ""; -} -Variant BakedIndirectLightGizmo::get_handle_value(int p_idx) const { - - return baker->get_extents(); -} -void BakedIndirectLightGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { - - Transform gt = baker->get_global_transform(); - //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); - - Vector3 extents = baker->get_extents(); - - Vector3 ray_from = p_camera->project_ray_origin(p_point); - Vector3 ray_dir = p_camera->project_ray_normal(p_point); - - Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) }; - - Vector3 axis; - axis[p_idx] = 1.0; - - Vector3 ra, rb; - Geometry::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb); - float d = ra[p_idx]; - if (d < 0.001) - d = 0.001; +//// - extents[p_idx] = d; - baker->set_extents(extents); +NavigationMeshSpatialGizmoPlugin::NavigationMeshSpatialGizmoPlugin() { + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1))); + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7))); + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4))); + create_material("navigation_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4))); } -void BakedIndirectLightGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - - Vector3 restore = p_restore; - - if (p_cancel) { - baker->set_extents(restore); - return; - } - - UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Change Probe Extents")); - ur->add_do_method(baker, "set_extents", baker->get_extents()); - ur->add_undo_method(baker, "set_extents", restore); - ur->commit_action(); +bool NavigationMeshSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<NavigationMeshInstance>(p_spatial) != NULL; } -void BakedIndirectLightGizmo::redraw() { - - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/baked_indirect_light"); - Ref<Material> material = create_material("baked_indirect_light_material", gizmo_color); - Ref<Material> icon = create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoBakedLightmap", "EditorIcons")); - Color gizmo_color_internal = gizmo_color; - gizmo_color_internal.a = 0.1; - Ref<Material> material_internal = create_material("baked_indirect_light_internal_material", gizmo_color_internal); - - clear(); - - Vector<Vector3> lines; - Vector3 extents = baker->get_extents(); - - AABB aabb = AABB(-extents, extents * 2); - - for (int i = 0; i < 12; i++) { - Vector3 a, b; - aabb.get_edge(i, a, b); - lines.push_back(a); - lines.push_back(b); - } - - add_lines(lines, material); - add_collision_segments(lines); - - Vector<Vector3> handles; - - for (int i = 0; i < 3; i++) { - - Vector3 ax; - ax[i] = aabb.position[i] + aabb.size[i]; - handles.push_back(ax); - } - - if (is_selected()) { - - gizmo_color.a = 0.1; - Ref<Material> solid_material = create_material("baked_indirect_light_solid_material", gizmo_color); - add_solid_box(solid_material, aabb.get_size()); - } - - add_unscaled_billboard(icon, 0.05); - add_handles(handles); +String NavigationMeshSpatialGizmoPlugin::get_name() const { + return "NavigationMeshInstance"; } -BakedIndirectLightGizmo::BakedIndirectLightGizmo(BakedLightmap *p_baker) { - baker = p_baker; - set_spatial_node(p_baker); -} +void NavigationMeshSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { -//////// -void NavigationMeshSpatialGizmo::redraw() { + NavigationMeshInstance *navmesh = Object::cast_to<NavigationMeshInstance>(p_gizmo->get_spatial_node()); - Ref<Material> edge_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge")); - Ref<Material> edge_material_disabled = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled")); - Ref<Material> solid_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_solid")); - Ref<Material> solid_material_disabled = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled")); + Ref<Material> edge_material = get_material("navigation_material", p_gizmo); + Ref<Material> edge_material_disabled = get_material("navigation_material", p_gizmo); + Ref<Material> solid_material = get_material("navigation_material", p_gizmo); + Ref<Material> solid_material_disabled = get_material("navigation_material", p_gizmo); - clear(); + p_gizmo->clear(); Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh(); if (navmeshie.is_null()) return; @@ -3353,28 +3569,19 @@ void NavigationMeshSpatialGizmo::redraw() { tmesh->create(tmeshfaces); if (lines.size()) - add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled); - add_collision_triangles(tmesh); + p_gizmo->add_lines(lines, navmesh->is_enabled() ? edge_material : edge_material_disabled); + p_gizmo->add_collision_triangles(tmesh); Ref<ArrayMesh> m = memnew(ArrayMesh); Array a; a.resize(Mesh::ARRAY_MAX); a[0] = tmeshfaces; m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a); m->surface_set_material(0, navmesh->is_enabled() ? solid_material : solid_material_disabled); - add_mesh(m); - add_collision_segments(lines); -} - -NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh) { - - set_spatial_node(p_navmesh); - navmesh = p_navmesh; + p_gizmo->add_mesh(m); + p_gizmo->add_collision_segments(lines); } ////// -/// -/// -/// #define BODY_A_RADIUS 0.25 #define BODY_B_RADIUS 0.27 @@ -3625,38 +3832,169 @@ void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base } } -void PinJointSpatialGizmo::CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) { - float cs = 0.25; +//// - r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin); - r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin); +JointSpatialGizmoPlugin::JointSpatialGizmoPlugin() { + create_material("joint_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1))); + create_material("joint_body_a_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1))); + create_material("joint_body_b_material", EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1))); } -void PinJointSpatialGizmo::redraw() { +bool JointSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<Joint>(p_spatial) != NULL; +} - clear(); - Vector<Vector3> cursor_points; - CreateGizmo(Transform(), cursor_points); - add_collision_segments(cursor_points); +String JointSpatialGizmoPlugin::get_name() const { + return "Joints"; +} - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); +void JointSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + Joint *joint = Object::cast_to<Joint>(p_gizmo->get_spatial_node()); - add_lines(cursor_points, material); -} + p_gizmo->clear(); -PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint *p_p3d) { + const Spatial *node_body_a = Object::cast_to<Spatial>(joint->get_node(joint->get_node_a())); + const Spatial *node_body_b = Object::cast_to<Spatial>(joint->get_node(joint->get_node_b())); - p3d = p_p3d; - set_spatial_node(p3d); -} + Ref<Material> common_material = get_material("joint_material", p_gizmo); + Ref<Material> body_a_material = get_material("joint_body_a_material", p_gizmo); + Ref<Material> body_b_material = get_material("joint_body_b_material", p_gizmo); -//// + Vector<Vector3> points; + Vector<Vector3> body_a_points; + Vector<Vector3> body_b_points; -void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { + if (Object::cast_to<PinJoint>(joint)) { + CreatePinJointGizmo(Transform(), points); + p_gizmo->add_collision_segments(points); + p_gizmo->add_lines(points, common_material); + } + + HingeJoint *hinge = Object::cast_to<HingeJoint>(joint); + if (hinge) { + + CreateHingeJointGizmo( + Transform(), + hinge->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + hinge->get_param(HingeJoint::PARAM_LIMIT_LOWER), + hinge->get_param(HingeJoint::PARAM_LIMIT_UPPER), + hinge->get_flag(HingeJoint::FLAG_USE_LIMIT), + points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + SliderJoint *slider = Object::cast_to<SliderJoint>(joint); + if (slider) { + + CreateSliderJointGizmo( + Transform(), + slider->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER), + slider->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER), + slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER), + slider->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER), + points, + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + ConeTwistJoint *cone = Object::cast_to<ConeTwistJoint>(joint); + if (cone) { + + CreateConeTwistJointGizmo( + Transform(), + cone->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + cone->get_param(ConeTwistJoint::PARAM_SWING_SPAN), + cone->get_param(ConeTwistJoint::PARAM_TWIST_SPAN), + node_body_a ? &body_a_points : NULL, + node_body_b ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } + + Generic6DOFJoint *gen = Object::cast_to<Generic6DOFJoint>(joint); + if (gen) { + + CreateGeneric6DOFJointGizmo( + Transform(), + gen->get_global_transform(), + node_body_a ? node_body_a->get_global_transform() : Transform(), + node_body_b ? node_body_b->get_global_transform() : Transform(), + + gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), + gen->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), + gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), + gen->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), + gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), + gen->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), + + points, + node_body_a ? &body_a_points : NULL, + node_body_a ? &body_b_points : NULL); + + p_gizmo->add_collision_segments(points); + p_gizmo->add_collision_segments(body_a_points); + p_gizmo->add_collision_segments(body_b_points); + + p_gizmo->add_lines(points, common_material); + p_gizmo->add_lines(body_a_points, body_a_material); + p_gizmo->add_lines(body_b_points, body_b_material); + } +} + +void JointSpatialGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) { + float cs = 0.25; + + r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(-cs, 0, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, +cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, -cs, 0)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, +cs)).origin); + r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin); +} + +void JointSpatialGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin); r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin); @@ -3688,52 +4026,7 @@ void HingeJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transf } } -void HingeJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - Vector<Vector3> points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER), - p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER), - p3d->get_flag(HingeJoint::FLAG_USE_LIMIT), - points, - node_body_a ? &body_a_points : NULL, - node_body_b ? &body_b_points : NULL); - - clear(); - - Ref<Material> common_material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(points, common_material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void JointSpatialGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { p_linear_limit_lower = -p_linear_limit_lower; p_linear_limit_upper = -p_linear_limit_upper; @@ -3793,53 +4086,7 @@ void SliderJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Trans true); } -void SliderJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - clear(); - Vector<Vector3> cursor_points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER), - p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER), - p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER), - p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER), - cursor_points, - node_body_a ? &body_a_points : NULL, - node_body_b ? &body_b_points : NULL); - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(cursor_points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(cursor_points, material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void JointSpatialGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { if (r_body_a_points) JointGizmosDrawer::draw_cone( @@ -3858,51 +4105,7 @@ void ConeTwistJointSpatialGizmo::CreateGizmo(const Transform &p_offset, const Tr *r_body_b_points); } -void ConeTwistJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - clear(); - Vector<Vector3> points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN), - p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN), - points, - node_body_a ? &body_a_points : NULL, - node_body_b ? &body_b_points : NULL); - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(points, material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -void Generic6DOFJointSpatialGizmo::CreateGizmo( +void JointSpatialGizmoPlugin::CreateGeneric6DOFJointGizmo( const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, @@ -4051,510 +4254,3 @@ void Generic6DOFJointSpatialGizmo::CreateGizmo( #undef ADD_VTX } - -void Generic6DOFJointSpatialGizmo::redraw() { - - const Spatial *node_body_a = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_a())); - const Spatial *node_body_b = Object::cast_to<Spatial>(p3d->get_node(p3d->get_node_b())); - - clear(); - Vector<Vector3> cursor_points; - Vector<Vector3> body_a_points; - Vector<Vector3> body_b_points; - - CreateGizmo( - Transform(), - p3d->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), - - p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), - p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), - p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), - p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), - p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), - p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), - - p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), - p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), - p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), - p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), - p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), - p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), - - p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT), - p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT), - p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT), - p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT), - p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT), - p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT), - - cursor_points, - node_body_a ? &body_a_points : NULL, - node_body_a ? &body_b_points : NULL); - - Ref<Material> material = create_material("joint_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint")); - Ref<Material> body_a_material = create_material("joint_body_a_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_a")); - Ref<Material> body_b_material = create_material("joint_body_b_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/joint_body_b")); - - add_collision_segments(cursor_points); - add_collision_segments(body_a_points); - add_collision_segments(body_b_points); - - add_lines(cursor_points, material); - add_lines(body_a_points, body_a_material); - add_lines(body_b_points, body_b_material); -} - -Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d) { - - p3d = p_p3d; - set_spatial_node(p3d); -} - -/////// -/// -//// - -SpatialEditorGizmos *SpatialEditorGizmos::singleton = NULL; - -Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { - - if (Object::cast_to<Light>(p_spatial)) { - - Ref<LightSpatialGizmo> lsg = memnew(LightSpatialGizmo(Object::cast_to<Light>(p_spatial))); - return lsg; - } - - if (Object::cast_to<Camera>(p_spatial)) { - - Ref<CameraSpatialGizmo> lsg = memnew(CameraSpatialGizmo(Object::cast_to<Camera>(p_spatial))); - return lsg; - } - - if (Object::cast_to<Skeleton>(p_spatial)) { - - Ref<SkeletonSpatialGizmo> lsg = memnew(SkeletonSpatialGizmo(Object::cast_to<Skeleton>(p_spatial))); - return lsg; - } - - if (Object::cast_to<PhysicalBone>(p_spatial)) { - - Ref<PhysicalBoneSpatialGizmo> pbsg = memnew(PhysicalBoneSpatialGizmo(Object::cast_to<PhysicalBone>(p_spatial))); - return pbsg; - } - - if (Object::cast_to<Position3D>(p_spatial)) { - - Ref<Position3DSpatialGizmo> lsg = memnew(Position3DSpatialGizmo(Object::cast_to<Position3D>(p_spatial))); - return lsg; - } - - if (Object::cast_to<SoftBody>(p_spatial)) { - - Ref<SoftBodySpatialGizmo> misg = memnew(SoftBodySpatialGizmo(Object::cast_to<SoftBody>(p_spatial))); - return misg; - } - - if (Object::cast_to<MeshInstance>(p_spatial)) { - - Ref<MeshInstanceSpatialGizmo> misg = memnew(MeshInstanceSpatialGizmo(Object::cast_to<MeshInstance>(p_spatial))); - return misg; - } - - /*if (Object::cast_to<Room>(p_spatial)) { - - Ref<RoomSpatialGizmo> misg = memnew(RoomSpatialGizmo(Object::cast_to<Room>(p_spatial))); - return misg; - }*/ - - if (Object::cast_to<NavigationMeshInstance>(p_spatial)) { - - Ref<NavigationMeshSpatialGizmo> misg = memnew(NavigationMeshSpatialGizmo(Object::cast_to<NavigationMeshInstance>(p_spatial))); - return misg; - } - - if (Object::cast_to<RayCast>(p_spatial)) { - - Ref<RayCastSpatialGizmo> misg = memnew(RayCastSpatialGizmo(Object::cast_to<RayCast>(p_spatial))); - return misg; - } - /* - if (Object::cast_to<Portal>(p_spatial)) { - - Ref<PortalSpatialGizmo> misg = memnew(PortalSpatialGizmo(Object::cast_to<Portal>(p_spatial))); - return misg; - } -*/ - - if (Object::cast_to<CollisionShape>(p_spatial)) { - - Ref<CollisionShapeSpatialGizmo> misg = memnew(CollisionShapeSpatialGizmo(Object::cast_to<CollisionShape>(p_spatial))); - return misg; - } - - if (Object::cast_to<VisibilityNotifier>(p_spatial)) { - - Ref<VisibilityNotifierGizmo> misg = memnew(VisibilityNotifierGizmo(Object::cast_to<VisibilityNotifier>(p_spatial))); - return misg; - } - - if (Object::cast_to<Particles>(p_spatial)) { - - Ref<ParticlesGizmo> misg = memnew(ParticlesGizmo(Object::cast_to<Particles>(p_spatial))); - return misg; - } - - if (Object::cast_to<ReflectionProbe>(p_spatial)) { - - Ref<ReflectionProbeGizmo> misg = memnew(ReflectionProbeGizmo(Object::cast_to<ReflectionProbe>(p_spatial))); - return misg; - } - if (Object::cast_to<GIProbe>(p_spatial)) { - - Ref<GIProbeGizmo> misg = memnew(GIProbeGizmo(Object::cast_to<GIProbe>(p_spatial))); - return misg; - } - if (Object::cast_to<BakedLightmap>(p_spatial)) { - - Ref<BakedIndirectLightGizmo> misg = memnew(BakedIndirectLightGizmo(Object::cast_to<BakedLightmap>(p_spatial))); - return misg; - } - - if (Object::cast_to<VehicleWheel>(p_spatial)) { - - Ref<VehicleWheelSpatialGizmo> misg = memnew(VehicleWheelSpatialGizmo(Object::cast_to<VehicleWheel>(p_spatial))); - return misg; - } - if (Object::cast_to<PinJoint>(p_spatial)) { - - Ref<PinJointSpatialGizmo> misg = memnew(PinJointSpatialGizmo(Object::cast_to<PinJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<HingeJoint>(p_spatial)) { - - Ref<HingeJointSpatialGizmo> misg = memnew(HingeJointSpatialGizmo(Object::cast_to<HingeJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<SliderJoint>(p_spatial)) { - - Ref<SliderJointSpatialGizmo> misg = memnew(SliderJointSpatialGizmo(Object::cast_to<SliderJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<ConeTwistJoint>(p_spatial)) { - - Ref<ConeTwistJointSpatialGizmo> misg = memnew(ConeTwistJointSpatialGizmo(Object::cast_to<ConeTwistJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<Generic6DOFJoint>(p_spatial)) { - - Ref<Generic6DOFJointSpatialGizmo> misg = memnew(Generic6DOFJointSpatialGizmo(Object::cast_to<Generic6DOFJoint>(p_spatial))); - return misg; - } - - if (Object::cast_to<CollisionPolygon>(p_spatial)) { - - Ref<CollisionPolygonSpatialGizmo> misg = memnew(CollisionPolygonSpatialGizmo(Object::cast_to<CollisionPolygon>(p_spatial))); - return misg; - } - - if (Object::cast_to<AudioStreamPlayer3D>(p_spatial)) { - - Ref<AudioStreamPlayer3DSpatialGizmo> misg = memnew(AudioStreamPlayer3DSpatialGizmo(Object::cast_to<AudioStreamPlayer3D>(p_spatial))); - return misg; - } - - return Ref<SpatialEditorGizmo>(); -} - -SpatialEditorGizmos::SpatialEditorGizmos() { - - singleton = this; - - handle_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - handle_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - handle_material->set_on_top_of_alpha(); - handle_material->set_albedo(Color(0.8, 0.8, 0.8)); - handle_material_billboard = handle_material->duplicate(); - handle_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - handle2_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - handle2_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - handle2_material->set_flag(SpatialMaterial::FLAG_USE_POINT_SIZE, true); - handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle", "EditorIcons"); - handle2_material->set_point_size(handle_t->get_width()); - handle2_material->set_texture(SpatialMaterial::TEXTURE_ALBEDO, handle_t); - handle2_material->set_albedo(Color(1, 1, 1)); - handle2_material->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - handle2_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - handle2_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - handle2_material->set_on_top_of_alpha(); - handle2_material_billboard = handle2_material->duplicate(); - handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - handle2_material_billboard->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - handle2_material_billboard->set_on_top_of_alpha(); - - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/light", Color(1, 1, 0.2)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/skeleton", Color(1, 0.8, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_a", Color(0.6, 0.8, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint_body_b", Color(0.6, 0.9, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge_disabled", Color(0.7, 0.7, 0.7)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid", Color(0.5, 1, 1, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_solid_disabled", Color(0.7, 0.7, 0.7, 0.4)); - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.5)); - -#if 0 - light_material = create_line_material(Color(1, 1, 0.2)); - light_material_omni = create_line_material(Color(1, 1, 0.2)); - light_material_omni->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - light_material_omni_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - light_material_omni_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - light_material_omni_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - light_material_omni_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - light_material_omni_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - light_material_omni_icon->set_albedo(Color(1, 1, 1, 0.9)); - light_material_omni_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoLight", "EditorIcons")); - light_material_omni_icon->set_flag(SpatialMaterial::FLAG_FIXED_SIZE, true); - light_material_omni_icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - - light_material_directional_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - light_material_directional_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - light_material_directional_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - light_material_directional_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - light_material_directional_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - light_material_directional_icon->set_albedo(Color(1, 1, 1, 0.9)); - light_material_directional_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight", "EditorIcons")); - light_material_directional_icon->set_billboard_mode(SpatialMaterial::BILLBOARD_ENABLED); - light_material_directional_icon->set_depth_scale(1); - - camera_material = create_line_material(Color(1.0, 0.5, 1.0)); - - navmesh_edge_material = create_line_material(Color(0.1, 0.8, 1.0)); - navmesh_solid_material = create_solid_material(Color(0.1, 0.8, 1.0, 0.4)); - navmesh_edge_material->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false); - navmesh_edge_material->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false); - navmesh_solid_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - - navmesh_edge_material_disabled = create_line_material(Color(1.0, 0.8, 0.1)); - navmesh_solid_material_disabled = create_solid_material(Color(1.0, 0.8, 0.1, 0.4)); - navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, false); - navmesh_edge_material_disabled->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, false); - navmesh_solid_material_disabled->set_cull_mode(SpatialMaterial::CULL_DISABLED); - - skeleton_material = create_line_material(Color(0.6, 1.0, 0.3)); - skeleton_material->set_cull_mode(SpatialMaterial::CULL_DISABLED); - skeleton_material->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - skeleton_material->set_on_top_of_alpha(); - skeleton_material->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - - //position 3D Shared mesh - - pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - float cs = 0.25; - cursor_points.push_back(Vector3(+cs, 0, 0)); - cursor_points.push_back(Vector3(-cs, 0, 0)); - cursor_points.push_back(Vector3(0, +cs, 0)); - cursor_points.push_back(Vector3(0, -cs, 0)); - cursor_points.push_back(Vector3(0, 0, +cs)); - cursor_points.push_back(Vector3(0, 0, -cs)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - pos3d_mesh->surface_set_material(0, mat); - } - - listener_line_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - cursor_points.push_back(Vector3(0, 0, 0)); - cursor_points.push_back(Vector3(0, 0, -1.0)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - listener_line_mesh->surface_set_material(0, mat); - } - - room_material = create_line_material(Color(1.0, 0.6, 0.9)); - portal_material = create_line_material(Color(1.0, 0.8, 0.6)); - raycast_material = create_line_material(Color(1.0, 0.8, 0.6)); - car_wheel_material = create_line_material(Color(0.6, 0.8, 1.0)); - visibility_notifier_material = create_line_material(Color(1.0, 0.5, 1.0)); - particles_material = create_line_material(Color(1.0, 1.0, 0.5)); - reflection_probe_material = create_line_material(Color(0.5, 1.0, 0.7)); - reflection_probe_material_internal = create_line_material(Color(0.3, 0.8, 0.5, 0.15)); - gi_probe_material = create_line_material(Color(0.7, 1.0, 0.5)); - gi_probe_material_internal = create_line_material(Color(0.5, 0.8, 0.3, 0.1)); - joint_material = create_line_material(Color(0.6, 0.8, 1.0)); - - stream_player_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - stream_player_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - stream_player_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - stream_player_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - stream_player_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - stream_player_icon->set_albedo(Color(1, 1, 1, 0.9)); - stream_player_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer", "EditorIcons")); - - visibility_notifier_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - visibility_notifier_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - visibility_notifier_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - visibility_notifier_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - visibility_notifier_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - visibility_notifier_icon->set_albedo(Color(1, 1, 1, 0.9)); - visibility_notifier_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("Visible", "EditorIcons")); - - listener_icon = Ref<SpatialMaterial>(memnew(SpatialMaterial)); - listener_icon->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - listener_icon->set_cull_mode(SpatialMaterial::CULL_DISABLED); - listener_icon->set_depth_draw_mode(SpatialMaterial::DEPTH_DRAW_DISABLED); - listener_icon->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - listener_icon->set_albedo(Color(1, 1, 1, 0.9)); - listener_icon->set_texture(SpatialMaterial::TEXTURE_ALBEDO, SpatialEditor::get_singleton()->get_icon("GizmoListener", "EditorIcons")); - - { - - PoolVector<Vector3> vertices; - -#undef ADD_VTX -#define ADD_VTX(m_idx) \ - vertices.push_back(face_points[m_idx]); - - for (int i = 0; i < 6; i++) { - - Vector3 face_points[4]; - - for (int j = 0; j < 4; j++) { - - float v[3]; - v[0] = 1.0; - v[1] = 1 - 2 * ((j >> 1) & 1); - v[2] = v[1] * (1 - 2 * (j & 1)); - - for (int k = 0; k < 3; k++) { - - if (i < 3) - face_points[j][(i + k) % 3] = v[k]; - else - face_points[3 - j][(i + k) % 3] = -v[k]; - } - } - //tri 1 - ADD_VTX(0); - ADD_VTX(1); - ADD_VTX(2); - //tri 2 - ADD_VTX(2); - ADD_VTX(3); - ADD_VTX(0); - } - - test_cube_tm = Ref<TriangleMesh>(memnew(TriangleMesh)); - test_cube_tm->create(vertices); - } - - shape_material = create_line_material(Color(0.2, 1, 1.0)); -#endif - - pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - float cs = 0.25; - cursor_points.push_back(Vector3(+cs, 0, 0)); - cursor_points.push_back(Vector3(-cs, 0, 0)); - cursor_points.push_back(Vector3(0, +cs, 0)); - cursor_points.push_back(Vector3(0, -cs, 0)); - cursor_points.push_back(Vector3(0, 0, +cs)); - cursor_points.push_back(Vector3(0, 0, -cs)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(1, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 1, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 1, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - pos3d_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - pos3d_mesh->surface_set_material(0, mat); - } - - listener_line_mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); - { - - PoolVector<Vector3> cursor_points; - PoolVector<Color> cursor_colors; - cursor_points.push_back(Vector3(0, 0, 0)); - cursor_points.push_back(Vector3(0, 0, -1.0)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - cursor_colors.push_back(Color(0.5, 0.5, 0.5, 0.7)); - - Ref<SpatialMaterial> mat = memnew(SpatialMaterial); - mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); - mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); - mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); - mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); - mat->set_line_width(3); - Array d; - d.resize(VS::ARRAY_MAX); - d[Mesh::ARRAY_VERTEX] = cursor_points; - d[Mesh::ARRAY_COLOR] = cursor_colors; - listener_line_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, d); - listener_line_mesh->surface_set_material(0, mat); - } -} diff --git a/editor/spatial_editor_gizmos.h b/editor/spatial_editor_gizmos.h index 198d028516..877590b91d 100644 --- a/editor/spatial_editor_gizmos.h +++ b/editor/spatial_editor_gizmos.h @@ -55,187 +55,120 @@ class Camera; -class EditorSpatialGizmo : public SpatialEditorGizmo { +class LightSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(EditorSpatialGizmo, SpatialGizmo); + GDCLASS(LightSpatialGizmoPlugin, EditorSpatialGizmoPlugin); - struct Instance { - - RID instance; - Ref<ArrayMesh> mesh; - RID skeleton; - bool billboard; - bool unscaled; - bool can_intersect; - bool extra_margin; - Instance() { - - billboard = false; - unscaled = false; - can_intersect = false; - extra_margin = false; - } - - void create_instance(Spatial *p_base); - }; - - Vector<Vector3> collision_segments; - Ref<TriangleMesh> collision_mesh; - - struct Handle { - Vector3 pos; - bool billboard; - }; - - Vector<Vector3> handles; - Vector<Vector3> secondary_handles; - float selectable_icon_size = -1.0f; - bool billboard_handle; +public: + bool has_gizmo(Spatial *p_spatial); + String get_name() const; - bool valid; - Spatial *base; - Vector<Instance> instances; - Spatial *spatial_node; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + void redraw(EditorSpatialGizmo *p_gizmo); - void _set_spatial_node(Node *p_node) { set_spatial_node(Object::cast_to<Spatial>(p_node)); } + LightSpatialGizmoPlugin(); +}; -protected: - void add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material, bool p_billboard = false); - void add_mesh(const Ref<ArrayMesh> &p_mesh, bool p_billboard = false, const RID &p_skeleton = RID()); - void add_collision_segments(const Vector<Vector3> &p_lines); - void add_collision_triangles(const Ref<TriangleMesh> &p_tmesh); - void add_unscaled_billboard(const Ref<Material> &p_material, float p_scale = 1); - void add_handles(const Vector<Vector3> &p_handles, bool p_billboard = false, bool p_secondary = false); - void add_solid_box(Ref<Material> &p_material, Vector3 p_size, Vector3 p_position = Vector3()); +class AudioStreamPlayer3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - void set_spatial_node(Spatial *p_node); - const Spatial *get_spatial_node() const { return spatial_node; } + GDCLASS(AudioStreamPlayer3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin); - static void _bind_methods(); +public: + bool has_gizmo(Spatial *p_spatial); + String get_name() const; - Ref<SpatialMaterial> create_material(const String &p_name, const Color &p_color, bool p_billboard = false, bool p_on_top = false, bool p_use_vertex_color = false); - Ref<SpatialMaterial> create_icon_material(const String &p_name, const Ref<Texture> &p_texture, bool p_on_top = false, const Color &p_albedo = Color(1, 1, 1, 1)); + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + void redraw(EditorSpatialGizmo *p_gizmo); -public: - virtual Vector3 get_handle_pos(int p_idx) const; - virtual bool intersect_frustum(const Camera *p_camera, const Vector<Plane> &p_frustum); - virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); - - void clear(); - void create(); - void transform(); - virtual void redraw(); - void free(); - virtual bool is_editable() const; - virtual bool can_draw() const; - - EditorSpatialGizmo(); - ~EditorSpatialGizmo(); + AudioStreamPlayer3DSpatialGizmoPlugin(); }; -class LightSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(LightSpatialGizmo, EditorSpatialGizmo); +class CameraSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Light *light; + GDCLASS(CameraSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; - void redraw(); - LightSpatialGizmo(Light *p_light = NULL); -}; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + void redraw(EditorSpatialGizmo *p_gizmo); -class AudioStreamPlayer3DSpatialGizmo : public EditorSpatialGizmo { + CameraSpatialGizmoPlugin(); +}; - GDCLASS(AudioStreamPlayer3DSpatialGizmo, EditorSpatialGizmo); +class MeshInstanceSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - AudioStreamPlayer3D *player; + GDCLASS(MeshInstanceSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool can_be_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - AudioStreamPlayer3DSpatialGizmo(AudioStreamPlayer3D *p_player = NULL); + MeshInstanceSpatialGizmoPlugin(); }; -class CameraSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(CameraSpatialGizmo, EditorSpatialGizmo); +class Sprite3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Camera *camera; + GDCLASS(Sprite3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool can_be_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - CameraSpatialGizmo(Camera *p_camera = NULL); + Sprite3DSpatialGizmoPlugin(); }; -class MeshInstanceSpatialGizmo : public EditorSpatialGizmo { +class Position3DSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(MeshInstanceSpatialGizmo, EditorSpatialGizmo); + GDCLASS(Position3DSpatialGizmoPlugin, EditorSpatialGizmoPlugin); - MeshInstance *mesh; + Ref<ArrayMesh> pos3d_mesh; + Vector<Vector3> cursor_points; public: - virtual bool can_draw() const; - void redraw(); - MeshInstanceSpatialGizmo(MeshInstance *p_mesh = NULL); -}; - -class Sprite3DSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(Sprite3DSpatialGizmo, EditorSpatialGizmo); - - SpriteBase3D *sprite; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); -public: - virtual bool can_draw() const; - void redraw(); - Sprite3DSpatialGizmo(SpriteBase3D *p_sprite = NULL); + Position3DSpatialGizmoPlugin(); }; -class Position3DSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(Position3DSpatialGizmo, EditorSpatialGizmo); +class SkeletonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Position3D *p3d; + GDCLASS(SkeletonSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - Position3DSpatialGizmo(Position3D *p_p3d = NULL); -}; - -class SkeletonSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(SkeletonSpatialGizmo, EditorSpatialGizmo); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - Skeleton *skel; - -public: - void redraw(); - SkeletonSpatialGizmo(Skeleton *p_skel = NULL); + SkeletonSpatialGizmoPlugin(); }; -class PhysicalBoneSpatialGizmo : public EditorSpatialGizmo { - GDCLASS(PhysicalBoneSpatialGizmo, EditorSpatialGizmo); +class PhysicalBoneSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - PhysicalBone *physical_bone; + GDCLASS(PhysicalBoneSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - //virtual Transform get_global_gizmo_transform(); - virtual void redraw(); - PhysicalBoneSpatialGizmo(PhysicalBone *p_pb = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + PhysicalBoneSpatialGizmoPlugin(); }; #if 0 @@ -251,154 +184,166 @@ public: }; #endif -class VisibilityNotifierGizmo : public EditorSpatialGizmo { - - GDCLASS(VisibilityNotifierGizmo, EditorSpatialGizmo); +class RayCastSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - VisibilityNotifier *notifier; + GDCLASS(RayCastSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - VisibilityNotifierGizmo(VisibilityNotifier *p_notifier = NULL); + RayCastSpatialGizmoPlugin(); }; -class ParticlesGizmo : public EditorSpatialGizmo { - - GDCLASS(ParticlesGizmo, EditorSpatialGizmo); +class VehicleWheelSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - Particles *particles; + GDCLASS(VehicleWheelSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - ParticlesGizmo(Particles *p_particles = NULL); + VehicleWheelSpatialGizmoPlugin(); }; -class ReflectionProbeGizmo : public EditorSpatialGizmo { - - GDCLASS(ReflectionProbeGizmo, EditorSpatialGizmo); +class SoftBodySpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - ReflectionProbe *probe; + GDCLASS(SoftBodySpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool is_selectable_when_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - ReflectionProbeGizmo(ReflectionProbe *p_probe = NULL); -}; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel); + bool is_gizmo_handle_highlighted(const EditorSpatialGizmo *p_gizmo, int idx) const; -class GIProbeGizmo : public EditorSpatialGizmo { + SoftBodySpatialGizmoPlugin(); +}; - GDCLASS(GIProbeGizmo, EditorSpatialGizmo); +class VisibilityNotifierGizmoPlugin : public EditorSpatialGizmoPlugin { - GIProbe *probe; + GDCLASS(VisibilityNotifierGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - GIProbeGizmo(GIProbe *p_probe = NULL); -}; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); -class BakedIndirectLightGizmo : public EditorSpatialGizmo { + VisibilityNotifierGizmoPlugin(); +}; - GDCLASS(BakedIndirectLightGizmo, EditorSpatialGizmo); +class ParticlesGizmoPlugin : public EditorSpatialGizmoPlugin { - BakedLightmap *baker; + GDCLASS(ParticlesGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool is_selectable_when_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); - void redraw(); - BakedIndirectLightGizmo(BakedLightmap *p_baker = NULL); + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + + ParticlesGizmoPlugin(); }; -class SoftBodySpatialGizmo : public EditorSpatialGizmo { - GDCLASS(SoftBodySpatialGizmo, EditorSpatialGizmo); +class ReflectionProbeGizmoPlugin : public EditorSpatialGizmoPlugin { - class SoftBody *soft_body; - //RID physics_sphere_shape; // Used for raycast that doesn't work, in this moment, with softbody + GDCLASS(ReflectionProbeGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - virtual bool intersect_ray(Camera *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal, int *r_gizmo_handle = NULL, bool p_sec_first = false); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); - virtual bool is_gizmo_handle_highlighted(int idx) const; + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); - SoftBodySpatialGizmo(SoftBody *p_soft_physics_body = NULL); - ~SoftBodySpatialGizmo(); + ReflectionProbeGizmoPlugin(); }; -class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo); +class GIProbeGizmoPlugin : public EditorSpatialGizmoPlugin { - CollisionShape *cs; + GDCLASS(GIProbeGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - void redraw(); - CollisionShapeSpatialGizmo(CollisionShape *p_cs = NULL); -}; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); -class CollisionPolygonSpatialGizmo : public EditorSpatialGizmo { + GIProbeGizmoPlugin(); +}; - GDCLASS(CollisionPolygonSpatialGizmo, EditorSpatialGizmo); +class BakedIndirectLightGizmoPlugin : public EditorSpatialGizmoPlugin { - CollisionPolygon *polygon; + GDCLASS(BakedIndirectLightGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - CollisionPolygonSpatialGizmo(CollisionPolygon *p_polygon = NULL); -}; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); -class RayCastSpatialGizmo : public EditorSpatialGizmo { + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); + + BakedIndirectLightGizmoPlugin(); +}; - GDCLASS(RayCastSpatialGizmo, EditorSpatialGizmo); +class CollisionShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - RayCast *raycast; + GDCLASS(CollisionShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - RayCastSpatialGizmo(RayCast *p_raycast = NULL); -}; + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false); -class VehicleWheelSpatialGizmo : public EditorSpatialGizmo { + CollisionShapeSpatialGizmoPlugin(); +}; - GDCLASS(VehicleWheelSpatialGizmo, EditorSpatialGizmo); +class CollisionPolygonSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - VehicleWheel *car_wheel; + GDCLASS(CollisionPolygonSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - void redraw(); - VehicleWheelSpatialGizmo(VehicleWheel *p_car_wheel = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + CollisionPolygonSpatialGizmoPlugin(); }; -class NavigationMeshSpatialGizmo : public EditorSpatialGizmo { +class NavigationMeshSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(NavigationMeshSpatialGizmo, EditorSpatialGizmo); + GDCLASS(NavigationMeshSpatialGizmoPlugin, EditorSpatialGizmoPlugin); struct _EdgeKey { @@ -408,11 +353,12 @@ class NavigationMeshSpatialGizmo : public EditorSpatialGizmo { bool operator<(const _EdgeKey &p_with) const { return from == p_with.from ? to < p_with.to : from < p_with.from; } }; - NavigationMeshInstance *navmesh; - public: - void redraw(); - NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + NavigationMeshSpatialGizmoPlugin(); }; class JointGizmosDrawer { @@ -421,7 +367,7 @@ public: static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform); static Basis look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform); static Basis look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform); - /// Special function just used for physics joints, it that returns a basis constrained toward Joint Z axis + /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis /// with axis X and Y that are looking toward the body and oriented toward up static Basis look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform); @@ -430,66 +376,20 @@ public: static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points); }; -class PinJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(PinJointSpatialGizmo, EditorSpatialGizmo); - - PinJoint *p3d; - -public: - static void CreateGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points); - - void redraw(); - PinJointSpatialGizmo(PinJoint *p_p3d = NULL); -}; - -class HingeJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(HingeJointSpatialGizmo, EditorSpatialGizmo); - - HingeJoint *p3d; - -public: - static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - - void redraw(); - HingeJointSpatialGizmo(HingeJoint *p_p3d = NULL); -}; - -class SliderJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(SliderJointSpatialGizmo, EditorSpatialGizmo); - - SliderJoint *p3d; - -public: - static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - - void redraw(); - SliderJointSpatialGizmo(SliderJoint *p_p3d = NULL); -}; - -class ConeTwistJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(ConeTwistJointSpatialGizmo, EditorSpatialGizmo); +class JointSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - ConeTwistJoint *p3d; + GDCLASS(JointSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - static void CreateGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - - void redraw(); - ConeTwistJointSpatialGizmo(ConeTwistJoint *p_p3d = NULL); -}; - -class Generic6DOFJointSpatialGizmo : public EditorSpatialGizmo { - - GDCLASS(Generic6DOFJointSpatialGizmo, EditorSpatialGizmo); - - Generic6DOFJoint *p3d; - -public: - static void CreateGizmo( + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + static void CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points); + static void CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateGeneric6DOFJointGizmo( const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, @@ -516,26 +416,7 @@ public: Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - void redraw(); - Generic6DOFJointSpatialGizmo(Generic6DOFJoint *p_p3d = NULL); + JointSpatialGizmoPlugin(); }; -class SpatialEditorGizmos { - -public: - HashMap<String, Ref<SpatialMaterial> > material_cache; - - Ref<SpatialMaterial> handle2_material; - Ref<SpatialMaterial> handle2_material_billboard; - Ref<SpatialMaterial> handle_material; - Ref<SpatialMaterial> handle_material_billboard; - Ref<Texture> handle_t; - Ref<ArrayMesh> pos3d_mesh; - Ref<ArrayMesh> listener_line_mesh; - static SpatialEditorGizmos *singleton; - - Ref<SpatialEditorGizmo> get_gizmo(Spatial *p_spatial); - - SpatialEditorGizmos(); -}; #endif // SPATIAL_EDITOR_GIZMOS_H diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index 9263a9ba6d..0857635492 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -644,20 +644,6 @@ float BulletPhysicsServer::body_get_param(RID p_body, BodyParameter p_param) con return body->get_param(p_param); } -void BulletPhysicsServer::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { - RigidBodyBullet *body = rigid_body_owner.get(p_body); - ERR_FAIL_COND(!body); - - body->set_combine_mode(p_param, p_mode); -} - -PhysicsServer::CombineMode BulletPhysicsServer::body_get_combine_mode(RID p_body, BodyParameter p_param) const { - RigidBodyBullet *body = rigid_body_owner.get(p_body); - ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); - - return body->get_combine_mode(p_param); -} - void BulletPhysicsServer::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { RigidBodyBullet *body = rigid_body_owner.get(p_body); ERR_FAIL_COND(!body); diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index 2c5b7e51cf..0e858ff311 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -213,9 +213,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value); virtual float body_get_param(RID p_body, BodyParameter p_param) const; - virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); - virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin); virtual real_t body_get_kinematic_safe_margin(RID p_body) const; diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 81a62edba6..9c0e802be5 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -265,8 +265,6 @@ RigidBodyBullet::RigidBodyBullet() : angularDamp(0), can_sleep(true), omit_forces_integration(false), - restitution_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT), - friction_combine_mode(PhysicsServer::COMBINE_MODE_INHERIT), force_integration_callback(NULL), isTransformChanged(false), previousActiveState(true), @@ -761,22 +759,6 @@ Vector3 RigidBodyBullet::get_angular_velocity() const { return gVec; } -void RigidBodyBullet::set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode) { - if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { - restitution_combine_mode = p_mode; - } else { - friction_combine_mode = p_mode; - } -} - -PhysicsServer::CombineMode RigidBodyBullet::get_combine_mode(PhysicsServer::BodyParameter p_param) const { - if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { - return restitution_combine_mode; - } else { - return friction_combine_mode; - } -} - void RigidBodyBullet::set_transform__bullet(const btTransform &p_global_transform) { if (mode == PhysicsServer::BODY_MODE_KINEMATIC) { // The kinematic use MotionState class diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index 35af3b90d8..f03009bce9 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -203,9 +203,6 @@ private: bool can_sleep; bool omit_forces_integration; - PhysicsServer::CombineMode restitution_combine_mode; - PhysicsServer::CombineMode friction_combine_mode; - Vector<CollisionData> collisions; // these parameters are used to avoid vector resize int maxCollisionsDetection; @@ -301,12 +298,6 @@ public: void set_angular_velocity(const Vector3 &p_velocity); Vector3 get_angular_velocity() const; - void set_combine_mode(const PhysicsServer::BodyParameter p_param, const PhysicsServer::CombineMode p_mode); - PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const; - - _FORCE_INLINE_ PhysicsServer::CombineMode get_restitution_combine_mode() const { return restitution_combine_mode; } - _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } - virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 1686a6e87e..9fc7230f91 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -123,7 +123,7 @@ void SoftBodyBullet::update_visual_server(SoftBodyVisualServerHandler *p_visual_ void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) { - if (p_mesh.is_null() || !p_mesh->surface_is_softbody_friendly(0)) + if (p_mesh.is_null()) soft_mesh.unref(); else soft_mesh = p_mesh; diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index 8454bea4eb..97228a972f 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -554,42 +554,12 @@ BulletPhysicsDirectSpaceState *SpaceBullet::get_direct_state() { btScalar calculateGodotCombinedRestitution(const btCollisionObject *body0, const btCollisionObject *body1) { - const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_restitution_combine_mode(); - - switch (cm) { - case PhysicsServer::COMBINE_MODE_INHERIT: - if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_restitution_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) - return calculateGodotCombinedRestitution(body1, body0); - // else use MAX [This is used when the two bodies doesn't use physical material] - case PhysicsServer::COMBINE_MODE_MAX: - return MAX(body0->getRestitution(), body1->getRestitution()); - case PhysicsServer::COMBINE_MODE_MIN: - return MIN(body0->getRestitution(), body1->getRestitution()); - case PhysicsServer::COMBINE_MODE_MULTIPLY: - return body0->getRestitution() * body1->getRestitution(); - default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: - return (body0->getRestitution() + body1->getRestitution()) / 2; - } + return CLAMP(body0->getRestitution() + body1->getRestitution(), 0, 1); } btScalar calculateGodotCombinedFriction(const btCollisionObject *body0, const btCollisionObject *body1) { - const PhysicsServer::CombineMode cm = static_cast<RigidBodyBullet *>(body0->getUserPointer())->get_friction_combine_mode(); - - switch (cm) { - case PhysicsServer::COMBINE_MODE_INHERIT: - if (static_cast<RigidBodyBullet *>(body1->getUserPointer())->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) - return calculateGodotCombinedFriction(body1, body0); - // else use MULTIPLY [This is used when the two bodies doesn't use physical material] - case PhysicsServer::COMBINE_MODE_MULTIPLY: - return body0->getFriction() * body1->getFriction(); - case PhysicsServer::COMBINE_MODE_MAX: - return MAX(body0->getFriction(), body1->getFriction()); - case PhysicsServer::COMBINE_MODE_MIN: - return MIN(body0->getFriction(), body1->getFriction()); - default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: - return (body0->getFriction() * body1->getFriction()) / 2; - } + return ABS(MIN(body0->getFriction(), body1->getFriction())); } void SpaceBullet::create_empty_world(bool p_create_soft_world) { diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 3b1ddfe4c0..f9744c72af 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -32,7 +32,16 @@ /////////// -String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const { +CSGShapeSpatialGizmoPlugin::CSGShapeSpatialGizmoPlugin() { + + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1)); + create_material("shape_material", gizmo_color); + create_handle_material("handles"); +} + +String CSGShapeSpatialGizmoPlugin::get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const { + + CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere>(cs)) { @@ -57,7 +66,9 @@ String CSGShapeSpatialGizmo::get_handle_name(int p_idx) const { return ""; } -Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const { +Variant CSGShapeSpatialGizmoPlugin::get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const { + + CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere>(cs)) { @@ -89,10 +100,12 @@ Variant CSGShapeSpatialGizmo::get_handle_value(int p_idx) const { return Variant(); } -void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) { +void CSGShapeSpatialGizmoPlugin::set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point) { + + CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); Transform gt = cs->get_global_transform(); - gt.orthonormalize(); + //gt.orthonormalize(); Transform gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); @@ -170,7 +183,9 @@ void CSGShapeSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 s->set_outer_radius(d); } } -void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { +void CSGShapeSpatialGizmoPlugin::commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + + CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); if (Object::cast_to<CSGSphere>(cs)) { CSGSphere *s = Object::cast_to<CSGSphere>(cs); @@ -260,12 +275,26 @@ void CSGShapeSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bo ur->commit_action(); } } -void CSGShapeSpatialGizmo::redraw() { +bool CSGShapeSpatialGizmoPlugin::has_gizmo(Spatial *p_spatial) { + return Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial); +} - clear(); +String CSGShapeSpatialGizmoPlugin::get_name() const { + return "CSGShapes"; +} + +bool CSGShapeSpatialGizmoPlugin::is_selectable_when_hidden() const { + return true; +} - Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/csg"); - Ref<Material> material = create_material("shape_material", gizmo_color); +void CSGShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) { + + CSGShape *cs = Object::cast_to<CSGShape>(p_gizmo->get_spatial_node()); + + p_gizmo->clear(); + + Ref<Material> material = get_material("shape_material", p_gizmo); + Ref<Material> handles_material = get_material("handles"); PoolVector<Vector3> faces = cs->get_brush_faces(); @@ -284,8 +313,8 @@ void CSGShapeSpatialGizmo::redraw() { } } - add_lines(lines, material); - add_collision_segments(lines); + p_gizmo->add_lines(lines, material); + p_gizmo->add_collision_segments(lines); if (Object::cast_to<CSGSphere>(cs)) { CSGSphere *s = Object::cast_to<CSGSphere>(cs); @@ -293,7 +322,7 @@ void CSGShapeSpatialGizmo::redraw() { float r = s->get_radius(); Vector<Vector3> handles; handles.push_back(Vector3(r, 0, 0)); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CSGBox>(cs)) { @@ -303,7 +332,7 @@ void CSGShapeSpatialGizmo::redraw() { handles.push_back(Vector3(s->get_width(), 0, 0)); handles.push_back(Vector3(0, s->get_height(), 0)); handles.push_back(Vector3(0, 0, s->get_depth())); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CSGCylinder>(cs)) { @@ -312,7 +341,7 @@ void CSGShapeSpatialGizmo::redraw() { Vector<Vector3> handles; handles.push_back(Vector3(s->get_radius(), 0, 0)); handles.push_back(Vector3(0, s->get_height() * 0.5, 0)); - add_handles(handles); + p_gizmo->add_handles(handles, handles_material); } if (Object::cast_to<CSGTorus>(cs)) { @@ -321,25 +350,11 @@ void CSGShapeSpatialGizmo::redraw() { Vector<Vector3> handles; handles.push_back(Vector3(s->get_inner_radius(), 0, 0)); handles.push_back(Vector3(s->get_outer_radius(), 0, 0)); - add_handles(handles); - } -} -CSGShapeSpatialGizmo::CSGShapeSpatialGizmo(CSGShape *p_cs) { - - cs = p_cs; - set_spatial_node(p_cs); -} - -Ref<SpatialEditorGizmo> EditorPluginCSG::create_spatial_gizmo(Spatial *p_spatial) { - if (Object::cast_to<CSGSphere>(p_spatial) || Object::cast_to<CSGBox>(p_spatial) || Object::cast_to<CSGCylinder>(p_spatial) || Object::cast_to<CSGTorus>(p_spatial) || Object::cast_to<CSGMesh>(p_spatial) || Object::cast_to<CSGPolygon>(p_spatial)) { - Ref<CSGShapeSpatialGizmo> csg = memnew(CSGShapeSpatialGizmo(Object::cast_to<CSGShape>(p_spatial))); - return csg; + p_gizmo->add_handles(handles, handles_material); } - - return Ref<SpatialEditorGizmo>(); } EditorPluginCSG::EditorPluginCSG(EditorNode *p_editor) { - - EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.2, 0.5, 1, 0.1)); + Ref<CSGShapeSpatialGizmoPlugin> gizmo_plugin = Ref<CSGShapeSpatialGizmoPlugin>(memnew(CSGShapeSpatialGizmoPlugin)); + SpatialEditor::get_singleton()->register_gizmo_plugin(gizmo_plugin); } diff --git a/modules/csg/csg_gizmos.h b/modules/csg/csg_gizmos.h index 68e916823b..d65d1f58c1 100644 --- a/modules/csg/csg_gizmos.h +++ b/modules/csg/csg_gizmos.h @@ -35,25 +35,27 @@ #include "editor/editor_plugin.h" #include "editor/spatial_editor_gizmos.h" -class CSGShapeSpatialGizmo : public EditorSpatialGizmo { +class CSGShapeSpatialGizmoPlugin : public EditorSpatialGizmoPlugin { - GDCLASS(CSGShapeSpatialGizmo, EditorSpatialGizmo); - - CSGShape *cs; + GDCLASS(CSGShapeSpatialGizmoPlugin, EditorSpatialGizmoPlugin); public: - virtual String get_handle_name(int p_idx) const; - virtual Variant get_handle_value(int p_idx) const; - virtual void set_handle(int p_idx, Camera *p_camera, const Point2 &p_point); - virtual void commit_handle(int p_idx, const Variant &p_restore, bool p_cancel = false); - void redraw(); - CSGShapeSpatialGizmo(CSGShape *p_cs = NULL); + bool has_gizmo(Spatial *p_spatial); + String get_name() const; + bool is_selectable_when_hidden() const; + void redraw(EditorSpatialGizmo *p_gizmo); + + String get_handle_name(const EditorSpatialGizmo *p_gizmo, int p_idx) const; + Variant get_handle_value(EditorSpatialGizmo *p_gizmo, int p_idx) const; + void set_handle(EditorSpatialGizmo *p_gizmo, int p_idx, Camera *p_camera, const Point2 &p_point); + void commit_handle(EditorSpatialGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel); + + CSGShapeSpatialGizmoPlugin(); }; class EditorPluginCSG : public EditorPlugin { GDCLASS(EditorPluginCSG, EditorPlugin) public: - virtual Ref<SpatialEditorGizmo> create_spatial_gizmo(Spatial *p_spatial); EditorPluginCSG(EditorNode *p_editor); }; diff --git a/modules/etc/image_etc.cpp b/modules/etc/image_etc.cpp index 8a674bc8c1..ddfa7af771 100644 --- a/modules/etc/image_etc.cpp +++ b/modules/etc/image_etc.cpp @@ -98,6 +98,33 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f Image::Format img_format = p_img->get_format(); Image::DetectChannels detected_channels = p_img->get_detected_channels(); + if (p_source == Image::COMPRESS_SOURCE_LAYERED) { + //keep what comes in + switch (p_img->get_format()) { + case Image::FORMAT_L8: { + detected_channels = Image::DETECTED_L; + } break; + case Image::FORMAT_LA8: { + detected_channels = Image::DETECTED_LA; + } break; + case Image::FORMAT_R8: { + detected_channels = Image::DETECTED_R; + } break; + case Image::FORMAT_RG8: { + detected_channels = Image::DETECTED_RG; + } break; + case Image::FORMAT_RGB8: { + detected_channels = Image::DETECTED_RGB; + } break; + case Image::FORMAT_RGBA8: + case Image::FORMAT_RGBA4444: + case Image::FORMAT_RGBA5551: { + detected_channels = Image::DETECTED_RGBA; + } break; + default: {} + } + } + if (p_source == Image::COMPRESS_SOURCE_SRGB && (detected_channels == Image::DETECTED_R || detected_channels == Image::DETECTED_RG)) { //R and RG do not support SRGB detected_channels = Image::DETECTED_RGB; @@ -147,7 +174,7 @@ static void _compress_etc(Image *p_img, float p_lossy_quality, bool force_etc1_f PoolVector<uint8_t>::Read r = img->get_data().read(); - int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps() ? -1 : 0); + int target_size = Image::get_image_data_size(imgw, imgh, etc_format, p_img->has_mipmaps()); int mmc = 1 + (p_img->has_mipmaps() ? Image::get_image_required_mipmaps(imgw, imgh, etc_format) : 0); PoolVector<uint8_t> dst_data; diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 23747af86b..0f3b497c94 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -1060,7 +1060,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const s->set_class_name(p_class_name); return Ref<NativeScript>(s); } -bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { +bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { return true; } diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index 1b39b63ad9..688ed295db 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -295,7 +295,7 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 816b0f0cab..2b538c4a36 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -108,7 +108,7 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const return script; } -bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { +bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { PoolStringArray functions; if (_desc.validate) { bool ret = _desc.validate( diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index 2443e31361..c4df6f3a33 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -74,7 +74,7 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index cff3be76ae..42ec05e6ce 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -181,7 +181,11 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Variant::CallErro bool GDScript::can_instance() const { - return valid || (!tool && !ScriptServer::is_scripting_enabled()); +#ifdef TOOLS_ENABLED + return valid && (tool || ScriptServer::is_scripting_enabled()); +#else + return valid; +#endif } Ref<Script> GDScript::get_base_script() const { @@ -310,27 +314,6 @@ bool GDScript::get_property_default_value(const StringName &p_property, Variant ScriptInstance *GDScript::instance_create(Object *p_this) { - if (!tool && !ScriptServer::is_scripting_enabled()) { - -#ifdef TOOLS_ENABLED - - //instance a fake script for editing the values - //plist.invert(); - - /*print_line("CREATING PLACEHOLDER"); - for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { - print_line(E->get().name); - }*/ - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); - placeholders.insert(si); - //_update_placeholder(si); - _update_exports(); - return si; -#else - return NULL; -#endif - } - GDScript *top = this; while (top->_base) top = top->_base; @@ -349,6 +332,27 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { Variant::CallError unchecked_error; return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); } + +PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) { +#ifdef TOOLS_ENABLED + + //instance a fake script for editing the values + //plist.invert(); + + /*print_line("CREATING PLACEHOLDER"); + for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { + print_line(E->get().name); + }*/ + PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); + placeholders.insert(si); + //_update_placeholder(si); + _update_exports(); + return si; +#else + return NULL; +#endif +} + bool GDScript::instance_has(const Object *p_this) const { #ifndef NO_THREADS @@ -480,6 +484,10 @@ bool GDScript::_update_exports() { for (int i = 0; i < c->_signals.size(); i++) { _signals[c->_signals[i].name] = c->_signals[i].arguments; } + } else { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(true); + } } } else { //print_line("unchanged is "+get_path()); @@ -501,7 +509,7 @@ bool GDScript::_update_exports() { _update_exports_values(values, propnames); for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - + E->get()->set_build_failed(false); E->get()->update(propnames, values); } } @@ -596,6 +604,13 @@ Error GDScript::reload(bool p_keep_state) { return err; } } +#if DEBUG_ENABLED + for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { + String msg = "Script warning: " + E->get().get_name() + " (" + path + ") line " + itos(E->get().line) + ": "; + msg += E->get().get_message(); + WARN_PRINTS(msg); + } +#endif valid = true; @@ -1867,6 +1882,162 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b return String(); } +#ifdef DEBUG_ENABLED +String GDScriptWarning::get_message() const { + +#define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String()); + + switch (code) { + case UNASSIGNED_VARIABLE_OP_ASSIGN: { + CHECK_SYMBOLS(1); + return "Using assignment with operation but the variable '" + symbols[0] + "' was not previously assigned a value."; + } break; + case UNASSIGNED_VARIABLE: { + CHECK_SYMBOLS(1); + return "The variable '" + symbols[0] + "' was used but never assigned a value."; + } break; + case UNUSED_VARIABLE: { + CHECK_SYMBOLS(1); + return "The local variable '" + symbols[0] + "' is declared but never used in the block."; + } break; + case UNUSED_CLASS_VARIABLE: { + CHECK_SYMBOLS(1); + return "The class variable '" + symbols[0] + "' is declared but never used in the script."; + } break; + case UNUSED_ARGUMENT: { + CHECK_SYMBOLS(2); + return "The argument '" + symbols[1] + "' is never used in the function '" + symbols[0] + "'."; + } break; + case UNREACHABLE_CODE: { + CHECK_SYMBOLS(1); + return "Unreachable code (statement after return) in function '" + symbols[0] + "()'."; + } break; + case STANDALONE_EXPRESSION: { + return "Standalone expression (the line has no effect)."; + } break; + case VOID_ASSIGNMENT: { + CHECK_SYMBOLS(1); + return "Assignment operation, but the function '" + symbols[0] + "()' returns void."; + } break; + case NARROWING_CONVERSION: { + return "Narrowing coversion (float is converted to int and lose precision)."; + } break; + case FUNCTION_MAY_YIELD: { + CHECK_SYMBOLS(1); + return "Assigned variable is typed but the function '" + symbols[0] + "()' may yield and return a GDScriptFunctionState instead."; + } break; + case VARIABLE_CONFLICTS_FUNCTION: { + CHECK_SYMBOLS(1); + return "Variable declaration of '" + symbols[0] + "' conflicts with a function of the same name."; + } break; + case FUNCTION_CONFLICTS_VARIABLE: { + CHECK_SYMBOLS(1); + return "Function declaration of '" + symbols[0] + "()' conflicts with a variable of the same name."; + } break; + case FUNCTION_CONFLICTS_CONSTANT: { + CHECK_SYMBOLS(1); + return "Function declaration of '" + symbols[0] + "()' conflicts with a constant of the same name."; + } break; + case INCOMPATIBLE_TERNARY: { + return "Values of the ternary conditional are not mutually compatible."; + } break; + case UNUSED_SIGNAL: { + CHECK_SYMBOLS(1); + return "The signal '" + symbols[0] + "' is declared but never emitted."; + } break; + case RETURN_VALUE_DISCARDED: { + CHECK_SYMBOLS(1); + return "The function '" + symbols[0] + "()' returns a value, but this value is never used."; + } break; + case PROPERTY_USED_AS_FUNCTION: { + CHECK_SYMBOLS(2); + return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a property with the same name. Did you mean to access it?"; + } break; + case CONSTANT_USED_AS_FUNCTION: { + CHECK_SYMBOLS(2); + return "The method '" + symbols[0] + "()' was not found in base '" + symbols[1] + "' but there's a constant with the same name. Did you mean to access it?"; + } break; + case FUNCTION_USED_AS_PROPERTY: { + CHECK_SYMBOLS(2); + return "The property '" + symbols[0] + "' was not found in base '" + symbols[1] + "' but there's a method with the same name. Did you mean to call it?"; + } break; + case INTEGER_DIVISION: { + return "Integer division, decimal part will be discarded."; + } break; + case UNSAFE_PROPERTY_ACCESS: { + CHECK_SYMBOLS(2); + return "The property '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype)."; + } break; + case UNSAFE_METHOD_ACCESS: { + CHECK_SYMBOLS(2); + return "The method '" + symbols[0] + "' is not present on the inferred type '" + symbols[1] + "' (but may be present on a subtype)."; + } break; + case UNSAFE_CAST: { + CHECK_SYMBOLS(1); + return "The value is cast to '" + symbols[0] + "' but has an unkown type."; + } break; + case UNSAFE_CALL_ARGUMENT: { + CHECK_SYMBOLS(4); + return "The argument '" + symbols[0] + "' of the function '" + symbols[1] + "' requires a the subtype '" + symbols[2] + "' but the supertype '" + symbols[3] + "' was provided"; + } break; + } + ERR_EXPLAIN("Invalid GDScript waring code: " + get_name_from_code(code)); + ERR_FAIL_V(String()); + +#undef CHECK_SYMBOLS +} + +String GDScriptWarning::get_name() const { + return get_name_from_code(code); +} + +String GDScriptWarning::get_name_from_code(Code p_code) { + ERR_FAIL_COND_V(p_code < 0 || p_code >= WARNING_MAX, String()); + + static const char *names[] = { + "UNASSIGNED_VARIABLE", + "UNASSIGNED_VARIABLE_OP_ASSIGN", + "UNUSED_VARIABLE", + "UNUSED_CLASS_VARIABLE", + "UNUSED_ARGUMENT", + "UNREACHABLE_CODE", + "STANDALONE_EXPRESSION", + "VOID_ASSIGNMENT", + "NARROWING_CONVERSION", + "FUNCTION_MAY_YIELD", + "VARIABLE_CONFLICTS_FUNCTION", + "FUNCTION_CONFLICTS_VARIABLE", + "FUNCTION_CONFLICTS_CONSTANT", + "INCOMPATIBLE_TERNARY", + "UNUSED_SIGNAL", + "RETURN_VALUE_DISCARDED", + "PROPERTY_USED_AS_FUNCTION", + "CONSTANT_USED_AS_FUNCTION", + "FUNCTION_USED_AS_PROPERTY", + "INTEGER_DIVISION", + "UNSAFE_PROPERTY_ACCESS", + "UNSAFE_METHOD_ACCESS", + "UNSAFE_CAST", + "UNSAFE_CALL_ARGUMENT", + NULL + }; + + return names[(int)p_code]; +} + +GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name) { + for (int i = 0; i < WARNING_MAX; i++) { + if (get_name_from_code((Code)i) == p_name) { + return (Code)i; + } + } + + ERR_EXPLAIN("Invalid GDScript waring name: " + p_name); + ERR_FAIL_V(WARNING_MAX); +} + +#endif // DEBUG_ENABLED + GDScriptLanguage::GDScriptLanguage() { calls = 0; @@ -1903,6 +2074,15 @@ GDScriptLanguage::GDScriptLanguage() { _debug_max_call_stack = 0; _call_stack = NULL; } + +#ifdef DEBUG_ENABLED + GLOBAL_DEF("debug/gdscript/warnings/enable", true); + GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false); + for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { + String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); + GLOBAL_DEF("debug/gdscript/warnings/" + warning, !warning.begins_with("unsafe_")); + } +#endif // DEBUG_ENABLED } GDScriptLanguage::~GDScriptLanguage() { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 79ac9ed413..68e89887b0 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -171,6 +171,7 @@ public: virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so virtual ScriptInstance *instance_create(Object *p_this); + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; virtual bool has_source_code() const; @@ -261,6 +262,49 @@ public: ~GDScriptInstance(); }; +#ifdef DEBUG_ENABLED +struct GDScriptWarning { + enum Code { + UNASSIGNED_VARIABLE, // Variable used but never assigned + UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc) + UNUSED_VARIABLE, // Local variable is declared but never used + UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file + UNUSED_ARGUMENT, // Function argument is never used + UNREACHABLE_CODE, // Code after a return statement + STANDALONE_EXPRESSION, // Expression not assigned to a variable + VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable + NARROWING_CONVERSION, // Float value into an integer slot, precision is lost + FUNCTION_MAY_YIELD, // Typed assign of function call that yields (it may return a function state) + VARIABLE_CONFLICTS_FUNCTION, // Variable has the same name of a function + FUNCTION_CONFLICTS_VARIABLE, // Function has the same name of a variable + FUNCTION_CONFLICTS_CONSTANT, // Function has the same name of a constant + INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible + UNUSED_SIGNAL, // Signal is defined but never emitted + RETURN_VALUE_DISCARDED, // Function call returns something but the value isn't used + PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name + CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name + FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name + INTEGER_DIVISION, // Integer divide by integer, decimal part is discarded + UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes) + UNSAFE_METHOD_ACCESS, // Fucntion not found in the detected type (but can be in subtypes) + UNSAFE_CAST, // Cast used in an unknown type + UNSAFE_CALL_ARGUMENT, // Function call argument is of a supertype of the require argument + WARNING_MAX, + } code; + Vector<String> symbols; + int line; + + String get_name() const; + String get_message() const; + static String get_name_from_code(Code p_code); + static Code get_code_from_name(const String &p_name); + + GDScriptWarning() : + line(-1), + code(WARNING_MAX) {} +}; +#endif // DEBUG_ENABLED + class GDScriptLanguage : public ScriptLanguage { static GDScriptLanguage *singleton; @@ -397,7 +441,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 2a42524ba7..abd56d2757 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -116,11 +116,24 @@ void GDScriptLanguage::make_template(const String &p_class_name, const String &p p_script->set_source_code(src); } -bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { +bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { GDScriptParser parser; Error err = parser.parse(p_script, p_path.get_base_dir(), true, p_path, false, r_safe_lines); +#ifdef DEBUG_ENABLED + if (r_warnings) { + for (const List<GDScriptWarning>::Element *E = parser.get_warnings().front(); E; E = E->next()) { + const GDScriptWarning &warn = E->get(); + ScriptLanguage::Warning w; + w.line = warn.line; + w.code = (int)warn.code; + w.string_code = GDScriptWarning::get_name_from_code(warn.code); + w.message = warn.get_message(); + r_warnings->push_back(w); + } + } +#endif if (err) { r_line_error = parser.get_error_line(); r_col_error = parser.get_error_column(); @@ -2442,7 +2455,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } break; case GDScriptParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { List<StringName> constants; - Variant::get_numeric_constants_for_type(parser.get_completion_built_in_constant(), &constants); + Variant::get_constants_for_type(parser.get_completion_built_in_constant(), &constants); for (List<StringName>::Element *E = constants.front(); E; E = E->next()) { options.insert(E->get().operator String()); } @@ -3065,7 +3078,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co case GDScriptParser::DataType::BUILTIN: { base_type.has_type = false; - if (Variant::has_numeric_constant(base_type.builtin_type, p_symbol)) { + if (Variant::has_constant(base_type.builtin_type, p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT; r_result.class_name = Variant::get_type_name(base_type.builtin_type); r_result.class_member = p_symbol; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 852d465206..e0ed2b332b 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -38,6 +38,7 @@ #include "io/resource_loader.h" #include "os/file_access.h" #include "print_string.h" +#include "project_settings.h" #include "script_language.h" template <class T> @@ -56,6 +57,8 @@ T *GDScriptParser::alloc_node() { return t; } +static String _find_function_name(const GDScriptParser::OperatorNode *p_call); + bool GDScriptParser::_end_statement() { if (tokenizer->get_token() == GDScriptTokenizer::TK_SEMICOLON) { @@ -607,7 +610,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s _set_error("Built-in type constant or static function expected after '.'"); return NULL; } - if (!Variant::has_numeric_constant(bi_type, identifier)) { + if (!Variant::has_constant(bi_type, identifier)) { if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN && Variant::is_method_const(bi_type, identifier) && @@ -642,7 +645,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } else { ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value = Variant::get_numeric_constant_value(bi_type, identifier); + cn->value = Variant::get_constant_value(bi_type, identifier); cn->datatype = _type_from_variant(cn->value); expr = cn; } @@ -726,7 +729,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } BlockNode *b = current_block; - while (b) { + while (!bfn && b) { if (b->variables.has(identifier)) { IdentifierNode *id = alloc_node<IdentifierNode>(); LocalVarNode *lv = b->variables[identifier]; @@ -736,6 +739,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s expr = id; bfn = true; +#ifdef DEBUG_ENABLED switch (tokenizer->get_token()) { case GDScriptTokenizer::TK_OP_ASSIGN_ADD: case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: @@ -747,15 +751,23 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: case GDScriptTokenizer::TK_OP_ASSIGN_SUB: { - if (lv->assignments == 0 && !lv->datatype.has_type) { - _set_error("Using assignment with operation on a variable that was never assigned."); - return NULL; + if (lv->assignments == 0) { + if (!lv->datatype.has_type) { + _set_error("Using assignment with operation on a variable that was never assigned."); + return NULL; + } + _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String()); } } // fallthrough case GDScriptTokenizer::TK_OP_ASSIGN: { lv->assignments += 1; + lv->usages--; // Assignment is not really usage + } break; + default: { + lv->usages++; } } +#endif // DEBUG_ENABLED break; } b = b->parent_block; @@ -785,6 +797,32 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s } if (!bfn) { +#ifdef DEBUG_ENABLED + if (current_function) { + int arg_idx = current_function->arguments.find(identifier); + if (arg_idx != -1) { + switch (tokenizer->get_token()) { + case GDScriptTokenizer::TK_OP_ASSIGN_ADD: + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_AND: + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_OR: + case GDScriptTokenizer::TK_OP_ASSIGN_BIT_XOR: + case GDScriptTokenizer::TK_OP_ASSIGN_DIV: + case GDScriptTokenizer::TK_OP_ASSIGN_MOD: + case GDScriptTokenizer::TK_OP_ASSIGN_MUL: + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: + case GDScriptTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: + case GDScriptTokenizer::TK_OP_ASSIGN_SUB: + case GDScriptTokenizer::TK_OP_ASSIGN: { + // Assignment is not really usage + current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] - 1; + } break; + default: { + current_function->arguments_usage.write[arg_idx] = current_function->arguments_usage[arg_idx] + 1; + } + } + } + } +#endif // DEBUG_ENABLED IdentifierNode *id = alloc_node<IdentifierNode>(); id->name = identifier; id->line = id_line; @@ -2601,6 +2639,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { pending_newline = -1; } +#ifdef DEBUG_ENABLED switch (token) { case GDScriptTokenizer::TK_EOF: case GDScriptTokenizer::TK_ERROR: @@ -2609,13 +2648,13 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { // will check later } break; default: { - // TODO: Make this a warning - /*if (p_block->has_return) { - _set_error("Unreacheable code."); - return; - }*/ + if (p_block->has_return && !current_function->has_unreachable_code) { + _add_warning(GDScriptWarning::UNREACHABLE_CODE, -1, current_function->name.operator String()); + current_function->has_unreachable_code = true; + } } break; } +#endif // DEBUG_ENABLED switch (token) { case GDScriptTokenizer::TK_EOF: p_block->end_line = tokenizer->get_token_line(); @@ -2728,6 +2767,7 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { c->line = var_line; assigned = c; } + lv->assign = assigned; //must be added later, to avoid self-referencing. p_block->variables.insert(n, lv); @@ -2745,6 +2785,8 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) { lv->assign_op = op; lv->assign = assigned; + lv->assign_op = op; + if (!_end_statement()) { _set_error("Expected end of statement (var)"); return; @@ -3513,6 +3555,17 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { } } +#ifdef DEBUG_ENABLED + if (p_class->constant_expressions.has(name)) { + _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_CONSTANT, -1, name); + } + for (int i = 0; i < p_class->variables.size(); i++) { + if (p_class->variables[i].identifier == name) { + _add_warning(GDScriptWarning::FUNCTION_CONFLICTS_VARIABLE, -1, name); + } + } +#endif // DEBUG_ENABLED + if (tokenizer->get_token() != GDScriptTokenizer::TK_PARENTHESIS_OPEN) { _set_error("Expected '(' after identifier (syntax: 'func <identifier>([arguments]):' )."); @@ -3524,6 +3577,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { Vector<StringName> arguments; Vector<DataType> argument_types; Vector<Node *> default_values; +#ifdef DEBUG_ENABLED + Vector<int> arguments_usage; +#endif // DEBUG_ENABLED int fnline = tokenizer->get_token_line(); @@ -3550,6 +3606,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { StringName argname = tokenizer->get_token_identifier(); arguments.push_back(argname); +#ifdef DEBUG_ENABLED + arguments_usage.push_back(0); +#endif // DEBUG_ENABLED tokenizer->advance(); @@ -3703,7 +3762,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { function->default_values = default_values; function->_static = _static; function->line = fnline; - +#ifdef DEBUG_ENABLED + function->arguments_usage = arguments_usage; +#endif // DEBUG_ENABLED function->rpc_mode = rpc_mode; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; @@ -3730,6 +3791,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { ClassNode::Signal sig; sig.name = tokenizer->get_token_identifier(); + sig.emissions = 0; + sig.line = tokenizer->get_token_line(); tokenizer->advance(); if (tokenizer->get_token() == GDScriptTokenizer::TK_PARENTHESIS_OPEN) { @@ -4413,6 +4476,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { member.expression = NULL; member._export.name = member.identifier; member.line = tokenizer->get_token_line(); + member.usages = 0; member.rpc_mode = rpc_mode; if (current_class->constant_expressions.has(member.identifier)) { @@ -4428,7 +4492,20 @@ void GDScriptParser::_parse_class(ClassNode *p_class) { return; } } - +#ifdef DEBUG_ENABLED + for (int i = 0; i < current_class->functions.size(); i++) { + if (current_class->functions[i]->name == member.identifier) { + _add_warning(GDScriptWarning::VARIABLE_CONFLICTS_FUNCTION, member.line, member.identifier); + break; + } + } + for (int i = 0; i < current_class->static_functions.size(); i++) { + if (current_class->static_functions[i]->name == member.identifier) { + _add_warning(GDScriptWarning::VARIABLE_CONFLICTS_FUNCTION, member.line, member.identifier); + break; + } + } +#endif // DEBUG_ENABLED tokenizer->advance(); rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; @@ -5689,11 +5766,26 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { node_type.has_type = true; node_type.kind = DataType::BUILTIN; node_type.builtin_type = Variant::ARRAY; +#ifdef DEBUG_ENABLED + // Check stuff inside the array + ArrayNode *an = static_cast<ArrayNode *>(p_node); + for (int i = 0; i < an->elements.size(); i++) { + _reduce_node_type(an->elements[i]); + } +#endif // DEBUG_ENABLED } break; case Node::TYPE_DICTIONARY: { node_type.has_type = true; node_type.kind = DataType::BUILTIN; node_type.builtin_type = Variant::DICTIONARY; +#ifdef DEBUG_ENABLED + // Check stuff inside the dictionarty + DictionaryNode *dn = static_cast<DictionaryNode *>(p_node); + for (int i = 0; i < dn->elements.size(); i++) { + _reduce_node_type(dn->elements[i].key); + _reduce_node_type(dn->elements[i].value); + } +#endif // DEBUG_ENABLED } break; case Node::TYPE_SELF: { node_type.has_type = true; @@ -5704,6 +5796,7 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { IdentifierNode *id = static_cast<IdentifierNode *>(p_node); if (id->declared_block) { node_type = id->declared_block->variables[id->name]->get_datatype(); + id->declared_block->variables[id->name]->usages += 1; } else if (id->name == "#match_value") { // It's a special id just for the match statetement, ignore break; @@ -5738,6 +5831,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { } } } else { +#ifdef DEBUG_ENABLED + _add_warning(GDScriptWarning::UNSAFE_CAST, cn->line, cn->cast_type.to_string()); +#endif // DEBUG_ENABLED _mark_line_as_unsafe(cn->line); } @@ -5864,6 +5960,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { op->line, op->column); return DataType(); } +#ifdef DEBUG_ENABLED + if (var_op == Variant::OP_DIVIDE && argument_a_type.has_type && argument_a_type.kind == DataType::BUILTIN && argument_a_type.builtin_type == Variant::INT && + argument_b_type.has_type && argument_b_type.kind == DataType::BUILTIN && argument_b_type.builtin_type == Variant::INT) { + _add_warning(GDScriptWarning::INTEGER_DIVISION, op->line); + } +#endif // DEBUG_ENABLED } break; // Ternary operators @@ -5882,10 +5984,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { node_type = true_type; } else if (_is_type_compatible(false_type, true_type)) { node_type = false_type; + } else { +#ifdef DEBUG_ENABLED + _add_warning(GDScriptWarning::INCOMPATIBLE_TERNARY, op->line); +#endif // DEBUG_ENABLED } - - // TODO: Warn if types aren't compatible - } break; // Assignment should never happen within an expression case OperatorNode::OP_ASSIGN: @@ -5948,6 +6051,11 @@ GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) { node_type = result; } else { node_type = _reduce_identifier_type(&base_type, member_id->name, op->line); +#ifdef DEBUG_ENABLED + if (!node_type.has_type) { + _add_warning(GDScriptWarning::UNSAFE_PROPERTY_ACCESS, op->line, member_id->name.operator String(), base_type.to_string()); + } +#endif // DEBUG_ENABLED } } else { _mark_line_as_unsafe(op->line); @@ -6367,6 +6475,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat if (!_is_type_compatible(arg_type, par_types[i], true)) { types_match = false; break; + } else { +#ifdef DEBUG_ENABLED + if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_types[i].kind == DataType::BUILTIN && par_types[i].builtin_type == Variant::REAL) { + _add_warning(GDScriptWarning::NARROWING_CONVERSION, p_call->line, Variant::get_type_name(tn->vtype)); + } + if (par_types[i].may_yield && p_call->arguments[i + 1]->type == Node::TYPE_OPERATOR) { + _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i + 1]))); + } +#endif // DEBUG_ENABLED } } @@ -6400,6 +6517,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat return_type = _type_from_property(mi.return_val, false); +#ifdef DEBUG_ENABLED + // Check all arguments beforehand to solve warnings + for (int i = 1; i < p_call->arguments.size(); i++) { + _reduce_node_type(p_call->arguments[i]); + } +#endif // DEBUG_ENABLED + // Check arguments is_vararg = mi.flags & METHOD_FLAG_VARARG; @@ -6426,6 +6550,13 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat ERR_FAIL_V(DataType()); } +#ifdef DEBUG_ENABLED + // Check all arguments beforehand to solve warnings + for (int i = arg_id + 1; i < p_call->arguments.size(); i++) { + _reduce_node_type(p_call->arguments[i]); + } +#endif // DEBUG_ENABLED + IdentifierNode *func_id = static_cast<IdentifierNode *>(p_call->arguments[arg_id]); callee_name = func_id->name; arg_count -= 1 + arg_id; @@ -6505,8 +6636,18 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat _set_error("Method '" + callee_name + "' is not declared in the current class.", p_call->line); return DataType(); } + DataType tmp_type; + valid = _get_member_type(original_type, func_id->name, tmp_type); + if (valid) { + if (tmp_type.is_constant) { + _add_warning(GDScriptWarning::CONSTANT_USED_AS_FUNCTION, p_call->line, callee_name, original_type.to_string()); + } else { + _add_warning(GDScriptWarning::PROPERTY_USED_AS_FUNCTION, p_call->line, callee_name, original_type.to_string()); + } + } + _add_warning(GDScriptWarning::UNSAFE_METHOD_ACCESS, p_call->line, callee_name, original_type.to_string()); _mark_line_as_unsafe(p_call->line); -#endif +#endif // DEBUG_ENABLED return DataType(); } @@ -6522,7 +6663,19 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat _set_error("Non-static function '" + String(callee_name) + "' can only be called from an instance.", p_call->line); return DataType(); } -#endif + + // Check signal emission for warnings + if (callee_name == "emit_signal" && p_call->op == OperatorNode::OP_CALL && p_call->arguments[0]->type == Node::TYPE_SELF && p_call->arguments.size() >= 3 && p_call->arguments[2]->type == Node::TYPE_CONSTANT) { + ConstantNode *sig = static_cast<ConstantNode *>(p_call->arguments[2]); + String emitted = sig->value.get_type() == Variant::STRING ? sig->value.operator String() : ""; + for (int i = 0; i < current_class->_signals.size(); i++) { + if (current_class->_signals[i].name == emitted) { + current_class->_signals.write[i].emissions += 1; + break; + } + } + } +#endif // DEBUG_ENABLED } break; } @@ -6547,8 +6700,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat continue; } + DataType arg_type = arg_types[i - arg_diff]; + if (!par_type.has_type) { _mark_line_as_unsafe(p_call->line); +#ifdef DEBUG_ENABLED + if (par_type.may_yield && p_call->arguments[i]->type == Node::TYPE_OPERATOR) { + _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, p_call->line, _find_function_name(static_cast<OperatorNode *>(p_call->arguments[i]))); + } +#endif // DEBUG_ENABLED } else if (!_is_type_compatible(arg_types[i - arg_diff], par_type, true)) { // Supertypes are acceptable for dynamic compliance if (!_is_type_compatible(par_type, arg_types[i - arg_diff])) { @@ -6560,6 +6720,12 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat } else { _mark_line_as_unsafe(p_call->line); } + } else { +#ifdef DEBUG_ENABLED + if (arg_type.kind == DataType::BUILTIN && arg_type.builtin_type == Variant::INT && par_type.kind == DataType::BUILTIN && par_type.builtin_type == Variant::REAL) { + _add_warning(GDScriptWarning::NARROWING_CONVERSION, p_call->line, callee_name); + } +#endif // DEBUG_ENABLED } } @@ -6795,6 +6961,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType DataType member_type; + for (int i = 0; i < current_class->variables.size(); i++) { + ClassNode::Member m = current_class->variables[i]; + if (current_class->variables[i].identifier == p_identifier) { + member_type = current_class->variables[i].data_type; + current_class->variables.write[i].usages += 1; + return member_type; + } + } + if (_get_member_type(base_type, p_identifier, member_type)) { return member_type; } @@ -6922,6 +7097,19 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType _set_error("Identifier '" + p_identifier.operator String() + "' is not declared in the current scope.", p_line); } +#ifdef DEBUG_ENABLED + { + DataType tmp_type; + List<DataType> arg_types; + int argcount; + bool _static; + bool vararg; + if (_get_function_signature(base_type, p_identifier, tmp_type, arg_types, argcount, _static, vararg)) { + _add_warning(GDScriptWarning::FUNCTION_USED_AS_PROPERTY, p_line, p_identifier.operator String(), base_type.to_string()); + } + } +#endif // DEBUG_ENABLED + _mark_line_as_unsafe(p_line); return DataType(); } @@ -7174,6 +7362,11 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { } } } +#ifdef DEBUG_ENABLED + if (p_function->arguments_usage[i] == 0) { + _add_warning(GDScriptWarning::UNUSED_ARGUMENT, p_function->line, p_function->name, p_function->arguments[i].operator String()); + } +#endif // DEBUG_ENABLED } if (!(p_function->name == "_init")) { @@ -7244,6 +7437,7 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) { if (p_function->has_yield) { // yield() will make the function return a GDScriptFunctionState, so the type is ambiguous p_function->return_type.has_type = false; + p_function->return_type.may_yield = true; } } @@ -7270,6 +7464,20 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { if (error_set) return; } +#ifdef DEBUG_ENABLED + // Warnings + for (int i = 0; i < p_class->variables.size(); i++) { + if (p_class->variables[i].usages == 0) { + _add_warning(GDScriptWarning::UNUSED_CLASS_VARIABLE, p_class->variables[i].line, p_class->variables[i].identifier); + } + } + for (int i = 0; i < p_class->_signals.size(); i++) { + if (p_class->_signals[i].emissions == 0) { + _add_warning(GDScriptWarning::UNUSED_SIGNAL, p_class->_signals[i].line, p_class->_signals[i].name); + } + } +#endif // DEBUG_ENABLED + // Inner classes for (int i = 0; i < p_class->subclasses.size(); i++) { current_class = p_class->subclasses[i]; @@ -7279,6 +7487,26 @@ void GDScriptParser::_check_class_blocks_types(ClassNode *p_class) { } } +#ifdef DEBUG_ENABLED +static String _find_function_name(const GDScriptParser::OperatorNode *p_call) { + switch (p_call->arguments[0]->type) { + case GDScriptParser::Node::TYPE_TYPE: { + return Variant::get_type_name(static_cast<GDScriptParser::TypeNode *>(p_call->arguments[0])->vtype); + } break; + case GDScriptParser::Node::TYPE_BUILT_IN_FUNCTION: { + return GDScriptFunctions::get_func_name(static_cast<GDScriptParser::BuiltInFunctionNode *>(p_call->arguments[0])->function); + } break; + default: { + int id_index = p_call->op == GDScriptParser::OperatorNode::OP_PARENT_CALL ? 0 : 1; + if (p_call->arguments.size() > id_index && p_call->arguments[id_index]->type == GDScriptParser::Node::TYPE_IDENTIFIER) { + return static_cast<GDScriptParser::IdentifierNode *>(p_call->arguments[id_index])->name; + } + } break; + } + return String(); +} +#endif // DEBUG_ENABLED + void GDScriptParser::_check_block_types(BlockNode *p_block) { Node *last_var_assign = NULL; @@ -7297,8 +7525,23 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { lv->datatype = _resolve_type(lv->datatype, lv->line); _mark_line_as_safe(lv->line); + last_var_assign = lv->assign; if (lv->assign) { DataType assign_type = _reduce_node_type(lv->assign); +#ifdef DEBUG_ENABLED + if (assign_type.has_type && assign_type.kind == DataType::BUILTIN && assign_type.builtin_type == Variant::NIL) { + if (lv->assign->type == Node::TYPE_OPERATOR) { + OperatorNode *call = static_cast<OperatorNode *>(lv->assign); + if (call->op == OperatorNode::OP_CALL || call->op == OperatorNode::OP_PARENT_CALL) { + _add_warning(GDScriptWarning::VOID_ASSIGNMENT, lv->line, _find_function_name(call)); + } + } + } + if (lv->datatype.has_type && assign_type.may_yield && lv->assign->type == Node::TYPE_OPERATOR) { + _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, lv->line, _find_function_name(static_cast<OperatorNode *>(lv->assign))); + } +#endif // DEBUG_ENABLED + if (!_is_type_compatible(lv->datatype, assign_type)) { // Try supertype test if (_is_type_compatible(assign_type, lv->datatype)) { @@ -7329,6 +7572,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { lv->assign = convert_call; lv->assign_op->arguments.write[1] = convert_call; +#ifdef DEBUG_ENABLED + if (lv->datatype.builtin_type == Variant::INT && assign_type.builtin_type == Variant::REAL) { + _add_warning(GDScriptWarning::NARROWING_CONVERSION, lv->line); + } +#endif // DEBUG_ENABLED } } if (lv->datatype.infer_type) { @@ -7343,15 +7591,6 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { _mark_line_as_unsafe(lv->line); } } - last_var_assign = lv->assign; - - // TODO: Make a warning - /* - if (lv->assignments == 0) { - _set_error("Variable '" + String(lv->name) + "' is never assigned.", lv->line); - return; - } - */ } break; case Node::TYPE_OPERATOR: { OperatorNode *op = static_cast<OperatorNode *>(statement); @@ -7417,6 +7656,19 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { } else { rh_type = _reduce_node_type(op->arguments[1]); } +#ifdef DEBUG_ENABLED + if (rh_type.has_type && rh_type.kind == DataType::BUILTIN && rh_type.builtin_type == Variant::NIL) { + if (op->arguments[1]->type == Node::TYPE_OPERATOR) { + OperatorNode *call = static_cast<OperatorNode *>(op->arguments[1]); + if (call->op == OperatorNode::OP_CALL || call->op == OperatorNode::OP_PARENT_CALL) { + _add_warning(GDScriptWarning::VOID_ASSIGNMENT, op->line, _find_function_name(call)); + } + } + } + if (lh_type.has_type && rh_type.may_yield && op->arguments[1]->type == Node::TYPE_OPERATOR) { + _add_warning(GDScriptWarning::FUNCTION_MAY_YIELD, op->line, _find_function_name(static_cast<OperatorNode *>(op->arguments[1]))); + } +#endif // DEBUG_ENABLED if (!_is_type_compatible(lh_type, rh_type)) { // Try supertype test @@ -7447,6 +7699,11 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { convert_call->arguments.push_back(tgt_type); op->arguments.write[1] = convert_call; +#ifdef DEBUG_ENABLED + if (lh_type.builtin_type == Variant::INT && rh_type.builtin_type == Variant::REAL) { + _add_warning(GDScriptWarning::NARROWING_CONVERSION, op->line); + } +#endif // DEBUG_ENABLED } } if (!rh_type.has_type && (op->op != OperatorNode::OP_ASSIGN || lh_type.has_type || op->arguments[0]->type == Node::TYPE_OPERATOR)) { @@ -7456,15 +7713,29 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { case OperatorNode::OP_CALL: case OperatorNode::OP_PARENT_CALL: { _mark_line_as_safe(op->line); - _reduce_function_call_type(op); + DataType func_type = _reduce_function_call_type(op); +#ifdef DEBUG_ENABLED + if (func_type.has_type && (func_type.kind != DataType::BUILTIN || func_type.builtin_type != Variant::NIL)) { + // Figure out function name for warning + String func_name = _find_function_name(op); + if (func_name.empty()) { + func_name == "<undetected name>"; + } + _add_warning(GDScriptWarning::RETURN_VALUE_DISCARDED, op->line, func_name); + } +#endif // DEBUG_ENABLED if (error_set) return; } break; + case OperatorNode::OP_YIELD: { + _mark_line_as_safe(op->line); + _reduce_node_type(op); + } break; default: { _mark_line_as_safe(op->line); _reduce_node_type(op); // Test for safety anyway - // TODO: Make this a warning - /*_set_error("Standalone expression, nothing is done in this line.", statement->line); - return; */ +#ifdef DEBUG_ENABLED + _add_warning(GDScriptWarning::STANDALONE_EXPRESSION, statement->line); +#endif // DEBUG_ENABLED } } } break; @@ -7531,9 +7802,9 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { default: { _mark_line_as_safe(statement->line); _reduce_node_type(statement); // Test for safety anyway - // TODO: Make this a warning - /* _set_error("Standalone expression, nothing is done in this line.", statement->line); - return; */ +#ifdef DEBUG_ENABLED + _add_warning(GDScriptWarning::STANDALONE_EXPRESSION, statement->line); +#endif // DEBUG_ENABLED } } } @@ -7545,6 +7816,18 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) { current_block = p_block; if (error_set) return; } + +#ifdef DEBUG_ENABLED + // Warnings check + for (Map<StringName, LocalVarNode *>::Element *E = p_block->variables.front(); E; E = E->next()) { + LocalVarNode *lv = E->get(); + if (lv->usages == 0) { + _add_warning(GDScriptWarning::UNUSED_VARIABLE, lv->line, lv->name); + } else if (lv->assignments == 0) { + _add_warning(GDScriptWarning::UNASSIGNED_VARIABLE, lv->line, lv->name); + } + } +#endif // DEBUG_ENABLED } void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) { @@ -7558,6 +7841,56 @@ void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) error_set = true; } +#ifdef DEBUG_ENABLED +void GDScriptParser::_add_warning(int p_code, int p_line, const String &p_symbol1, const String &p_symbol2, const String &p_symbol3, const String &p_symbol4) { + Vector<String> symbols; + if (!p_symbol1.empty()) { + symbols.push_back(p_symbol1); + } + if (!p_symbol2.empty()) { + symbols.push_back(p_symbol2); + } + if (!p_symbol3.empty()) { + symbols.push_back(p_symbol3); + } + if (!p_symbol4.empty()) { + symbols.push_back(p_symbol4); + } + _add_warning(p_code, p_line, symbols); +} + +void GDScriptParser::_add_warning(int p_code, int p_line, const Vector<String> &p_symbols) { + if (tokenizer->is_ignoring_warnings() || !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) { + return; + } + String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower(); + if (tokenizer->get_warning_global_skips().has(warn_name)) { + return; + } + if (!GLOBAL_GET("debug/gdscript/warnings/" + warn_name)) { + return; + } + + GDScriptWarning warn; + warn.code = (GDScriptWarning::Code)p_code; + warn.symbols = p_symbols; + warn.line = p_line == -1 ? tokenizer->get_token_line() : p_line; + + List<GDScriptWarning>::Element *before = NULL; + for (List<GDScriptWarning>::Element *E = warnings.front(); E; E = E->next()) { + if (E->get().line > warn.line) { + break; + } + before = E; + } + if (before) { + warnings.insert_after(before, warn); + } else { + warnings.push_front(warn); + } +} +#endif // DEBUG_ENABLED + String GDScriptParser::get_error() const { return error; @@ -7624,6 +7957,37 @@ Error GDScriptParser::_parse(const String &p_base_path) { return ERR_PARSE_ERROR; } +#ifdef DEBUG_ENABLED + // Resolve warning ignores + Vector<Pair<int, String> > warning_skips = tokenizer->get_warning_skips(); + bool warning_is_error = GLOBAL_GET("debug/gdscript/warnings/treat_warnings_as_errors").booleanize(); + for (List<GDScriptWarning>::Element *E = warnings.front(); E;) { + GDScriptWarning &w = E->get(); + int skip_index = -1; + for (int i = 0; i < warning_skips.size(); i++) { + if (warning_skips[i].first >= w.line) { + break; + } + skip_index = i; + } + List<GDScriptWarning>::Element *next = E->next(); + bool erase = false; + if (skip_index != -1) { + if (warning_skips[skip_index].second == GDScriptWarning::get_name_from_code(w.code).to_lower()) { + erase = true; + } + warning_skips.remove(skip_index); + } + if (erase) { + warnings.erase(E); + } else if (warning_is_error) { + _set_error(w.get_message() + " (warning treated as error)", w.line); + return ERR_PARSE_ERROR; + } + E = next; + } +#endif // DEBUG_ENABLED + return OK; } diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 48f256b4c6..d8ee4e8159 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -38,6 +38,7 @@ #include "script_language.h" struct GDScriptDataType; +struct GDScriptWarning; class GDScriptParser { public: @@ -57,6 +58,7 @@ public: bool is_constant; bool is_meta_type; // Whether the value can be used as a type bool infer_type; + bool may_yield; // For function calls Variant::Type builtin_type; StringName native_type; @@ -95,6 +97,7 @@ public: is_constant(false), is_meta_type(false), infer_type(false), + may_yield(false), builtin_type(Variant::NIL), class_type(NULL) {} }; @@ -160,6 +163,7 @@ public: Node *expression; OperatorNode *initial_assignment; MultiplayerAPI::RPCMode rpc_mode; + int usages; }; struct Constant { Node *expression; @@ -169,6 +173,8 @@ public: struct Signal { StringName name; Vector<StringName> arguments; + int emissions; + int line; }; Vector<ClassNode *> subclasses; @@ -197,12 +203,16 @@ public: bool _static; MultiplayerAPI::RPCMode rpc_mode; bool has_yield; + bool has_unreachable_code; StringName name; DataType return_type; Vector<StringName> arguments; Vector<DataType> argument_types; Vector<Node *> default_values; BlockNode *body; +#ifdef DEBUG_ENABLED + Vector<int> arguments_usage; +#endif // DEBUG_ENABLED virtual DataType get_datatype() const { return return_type; } virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; } @@ -212,6 +222,7 @@ public: _static = false; rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED; has_yield = false; + has_unreachable_code = false; } }; @@ -267,6 +278,7 @@ public: Node *assign; OperatorNode *assign_op; int assignments; + int usages; DataType datatype; virtual DataType get_datatype() const { return datatype; } virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; } @@ -275,6 +287,7 @@ public: assign = NULL; assign_op = NULL; assignments = 0; + usages = 0; } }; @@ -518,6 +531,10 @@ private: Set<int> *safe_lines; #endif // DEBUG_ENABLED +#ifdef DEBUG_ENABLED + List<GDScriptWarning> warnings; +#endif // DEBUG_ENABLED + int pending_newline; List<int> tab_level; @@ -550,6 +567,10 @@ private: MultiplayerAPI::RPCMode rpc_mode; void _set_error(const String &p_error, int p_line = -1, int p_column = -1); +#ifdef DEBUG_ENABLED + void _add_warning(int p_code, int p_line = -1, const String &p_symbol1 = String(), const String &p_symbol2 = String(), const String &p_symbol3 = String(), const String &p_symbol4 = String()); + void _add_warning(int p_code, int p_line, const Vector<String> &p_symbols); +#endif // DEBUG_ENABLED bool _recover_from_completion(); bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false); @@ -605,6 +626,9 @@ public: String get_error() const; int get_error_line() const; int get_error_column() const; +#ifdef DEBUG_ENABLED + const List<GDScriptWarning> &get_warnings() const { return warnings; } +#endif // DEBUG_ENABLED Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = NULL); Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = ""); diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp index 7ae7c72ed3..537a0c5eaf 100644 --- a/modules/gdscript/gdscript_tokenizer.cpp +++ b/modules/gdscript/gdscript_tokenizer.cpp @@ -526,8 +526,13 @@ void GDScriptTokenizerText::_advance() { return; } case '#': { // line comment skip - +#ifdef DEBUG_ENABLED + String comment; +#endif // DEBUG_ENABLED while (GETCHAR(0) != '\n') { +#ifdef DEBUG_ENABLED + comment += GETCHAR(0); +#endif // DEBUG_ENABLED code_pos++; if (GETCHAR(0) == 0) { //end of file //_make_error("Unterminated Comment"); @@ -535,6 +540,17 @@ void GDScriptTokenizerText::_advance() { return; } } +#ifdef DEBUG_ENABLED + if (comment.begins_with("#warning-ignore:")) { + String code = comment.get_slice(":", 1); + warning_skips.push_back(Pair<int, String>(line, code.strip_edges().to_lower())); + } else if (comment.begins_with("#warning-ignore-all:")) { + String code = comment.get_slice(":", 1); + warning_global_skips.insert(code.strip_edges().to_lower()); + } else if (comment.strip_edges() == "#warnings-disable") { + ignore_warnings = true; + } +#endif // DEBUG_ENABLED INCPOS(1); column = 1; line++; @@ -1045,6 +1061,9 @@ void GDScriptTokenizerText::set_code(const String &p_code) { column = 1; //the same holds for columns tk_rb_pos = 0; error_flag = false; +#ifdef DEBUG_ENABLED + ignore_warnings = false; +#endif // DEBUG_ENABLED last_error = ""; for (int i = 0; i < MAX_LOOKAHEAD + 1; i++) _advance(); diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h index 5bd303224c..28a08bfaf8 100644 --- a/modules/gdscript/gdscript_tokenizer.h +++ b/modules/gdscript/gdscript_tokenizer.h @@ -31,6 +31,7 @@ #ifndef GDSCRIPT_TOKENIZER_H #define GDSCRIPT_TOKENIZER_H +#include "core/pair.h" #include "gdscript_functions.h" #include "string_db.h" #include "ustring.h" @@ -171,6 +172,11 @@ public: virtual int get_token_line_indent(int p_offset = 0) const = 0; virtual String get_token_error(int p_offset = 0) const = 0; virtual void advance(int p_amount = 1) = 0; +#ifdef DEBUG_ENABLED + virtual const Vector<Pair<int, String> > &get_warning_skips() const = 0; + virtual const Set<String> &get_warning_global_skips() const = 0; + virtual const bool is_ignoring_warnings() const = 0; +#endif // DEBUG_ENABLED virtual ~GDScriptTokenizer(){}; }; @@ -190,6 +196,7 @@ class GDScriptTokenizerText : public GDScriptTokenizer { union { Variant::Type vtype; //for type types GDScriptFunctions::Function func; //function for built in functions + int warning_code; //for warning skip }; int line, col; TokenData() { @@ -217,6 +224,11 @@ class GDScriptTokenizerText : public GDScriptTokenizer { int tk_rb_pos; String last_error; bool error_flag; +#ifdef DEBUG_ENABLED + Vector<Pair<int, String> > warning_skips; + Set<String> warning_global_skips; + bool ignore_warnings; +#endif // DEBUG_ENABLED void _advance(); @@ -232,6 +244,11 @@ public: virtual const Variant &get_token_constant(int p_offset = 0) const; virtual String get_token_error(int p_offset = 0) const; virtual void advance(int p_amount = 1); +#ifdef DEBUG_ENABLED + virtual const Vector<Pair<int, String> > &get_warning_skips() const { return warning_skips; } + virtual const Set<String> &get_warning_global_skips() const { return warning_global_skips; } + virtual const bool is_ignoring_warnings() const { return ignore_warnings; } +#endif // DEBUG_ENABLED }; class GDScriptTokenizerBuffer : public GDScriptTokenizer { @@ -265,6 +282,11 @@ public: virtual const Variant &get_token_constant(int p_offset = 0) const; virtual String get_token_error(int p_offset = 0) const; virtual void advance(int p_amount = 1); +#ifdef DEBUG_ENABLED + virtual const Vector<Pair<int, String> > &get_warning_skips() const { return Vector<Pair<int, String> >(); } + virtual const Set<String> &get_warning_global_skips() const { return Set<String>(); } + virtual const bool is_ignoring_warnings() const { return true; } +#endif // DEBUG_ENABLED GDScriptTokenizerBuffer(); }; diff --git a/modules/mono/config.py b/modules/mono/config.py index 9a000a2a72..c4f8dcfde8 100644 --- a/modules/mono/config.py +++ b/modules/mono/config.py @@ -83,6 +83,8 @@ def configure(env): mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0'] if env['platform'] == 'windows': + mono_root = '' + if bits == '32': if os.getenv('MONO32_PREFIX'): mono_root = os.getenv('MONO32_PREFIX') diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 7d7028a7a6..cd1a8266ed 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -736,6 +736,9 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { obj->get_script_instance()->get_property_state(state); map[obj->get_instance_id()] = state; obj->set_script(RefPtr()); + } else { + // no instance found. Let's remove it so we don't loop forever + E->get()->placeholders.erase(E->get()->placeholders.front()->get()); } } @@ -747,8 +750,24 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { } } - if (gdmono->reload_scripts_domain() != OK) + if (gdmono->reload_scripts_domain() != OK) { + // Failed to reload the scripts domain + // Make sure to add the scripts back to their owners before returning + for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { + Ref<CSharpScript> scr = E->key(); + for (Map<ObjectID, List<Pair<StringName, Variant> > >::Element *F = E->get().front(); F; F = F->next()) { + Object *obj = ObjectDB::get_instance(F->key()); + if (!obj) + continue; + obj->set_script(scr.get_ref_ptr()); + // Save reload state for next time if not saved + if (!scr->pending_reload_state.has(obj->get_instance_id())) { + scr->pending_reload_state[obj->get_instance_id()] = F->get(); + } + } + } return; + } for (Map<Ref<CSharpScript>, Map<ObjectID, List<Pair<StringName, Variant> > > >::Element *E = to_reload.front(); E; E = E->next()) { @@ -778,6 +797,14 @@ void CSharpLanguage::reload_assemblies_if_needed(bool p_soft_reload) { continue; } + if (scr->valid && scr->is_tool() && obj->get_script_instance()->is_placeholder()) { + // Script instance was a placeholder, but now the script was built successfully and is a tool script. + // We have to replace the placeholder with an actual C# script instance. + scr->placeholders.erase(static_cast<PlaceHolderScriptInstance *>(obj->get_script_instance())); + ScriptInstance *script_instance = scr->instance_create(obj); + obj->set_script_instance(script_instance); // Not necessary as it's already done in instance_create, but just in case... + } + for (List<Pair<StringName, Variant> >::Element *G = F->get().front(); G; G = G->next()) { obj->get_script_instance()->set(G->get().first, G->get().second); } @@ -1474,8 +1501,12 @@ void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED - if (!valid) + if (!valid) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(true); + } return false; + } bool changed = false; @@ -1577,6 +1608,7 @@ bool CSharpScript::_update_exports() { _update_exports_values(values, propnames); for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->set_build_failed(false); E->get()->update(propnames, values); } } @@ -1687,7 +1719,7 @@ bool CSharpScript::_get_member_export(GDMonoClass *p_class, GDMonoClassMember *p MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute)); - PropertyHint hint; + PropertyHint hint = PROPERTY_HINT_NONE; String hint_string; if (variant_type == Variant::NIL) { @@ -1873,7 +1905,11 @@ bool CSharpScript::can_instance() const { } #endif - return valid || (!tool && !ScriptServer::is_scripting_enabled()); +#ifdef TOOLS_ENABLED + return valid && (tool || ScriptServer::is_scripting_enabled()); +#else + return valid; +#endif } StringName CSharpScript::get_instance_base_type() const { @@ -1971,16 +2007,9 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Variant::Call ScriptInstance *CSharpScript::instance_create(Object *p_this) { - if (!tool && !ScriptServer::is_scripting_enabled()) { -#ifdef TOOLS_ENABLED - PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); - placeholders.insert(si); - _update_exports(); - return si; -#else - return NULL; +#ifdef DEBUG_ENABLED + CRASH_COND(!valid); #endif - } if (!script_class) { if (GDMono::get_singleton()->get_project_assembly() == NULL) { @@ -2011,6 +2040,18 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { return _create_instance(NULL, 0, p_this, Object::cast_to<Reference>(p_this), unchecked_error); } +PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) { + +#ifdef TOOLS_ENABLED + PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); + placeholders.insert(si); + _update_exports(); + return si; +#else + return NULL; +#endif +} + bool CSharpScript::instance_has(const Object *p_this) const { #ifndef NO_THREADS @@ -2077,9 +2118,11 @@ Error CSharpScript::reload(bool p_keep_state) { if (script_class) { #ifdef DEBUG_ENABLED - OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." + - script_class->get_name() + " for script " + get_path() + "\n") - .utf8()); + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print(String("Found class " + script_class->get_namespace() + "." + + script_class->get_name() + " for script " + get_path() + "\n") + .utf8()); + } #endif tool = script_class->has_attribute(CACHED_CLASS(ToolAttribute)); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 7f9732c297..53644eafae 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -139,6 +139,7 @@ public: virtual bool can_instance() const; virtual StringName get_instance_base_type() const; virtual ScriptInstance *instance_create(Object *p_this); + virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this); virtual bool instance_has(const Object *p_this) const; virtual bool has_source_code() const; @@ -292,7 +293,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines = NULL) const { return true; } + /* TODO */ virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const { return true; } virtual String validate_path(const String &p_path) const; virtual Script *create_script() const; virtual bool has_named_classes() const; diff --git a/modules/mono/glue/cs_files/Array.cs b/modules/mono/glue/cs_files/Array.cs index 51f57daef4..1ec4d7d20a 100644 --- a/modules/mono/glue/cs_files/Array.cs +++ b/modules/mono/glue/cs_files/Array.cs @@ -331,5 +331,10 @@ namespace Godot { return GetEnumerator(); } + + internal IntPtr GetPtr() + { + return objectArray.GetPtr(); + } } } diff --git a/modules/mono/glue/cs_files/Dictionary.cs b/modules/mono/glue/cs_files/Dictionary.cs index 57a1960ad9..30d17c2a59 100644 --- a/modules/mono/glue/cs_files/Dictionary.cs +++ b/modules/mono/glue/cs_files/Dictionary.cs @@ -397,5 +397,10 @@ namespace Godot { return GetEnumerator(); } + + internal IntPtr GetPtr() + { + return objectDict.GetPtr(); + } } } diff --git a/modules/mono/glue/cs_files/GD.cs b/modules/mono/glue/cs_files/GD.cs index e2457ff98b..0a5d703f27 100644 --- a/modules/mono/glue/cs_files/GD.cs +++ b/modules/mono/glue/cs_files/GD.cs @@ -64,6 +64,11 @@ namespace Godot return ResourceLoader.Load(path); } + public static T Load<T>(string path) where T : Godot.Resource + { + return (T) ResourceLoader.Load(path); + } + public static void Print(params object[] what) { NativeCalls.godot_icall_Godot_print(what); @@ -187,10 +192,5 @@ namespace Godot { return NativeCalls.godot_icall_Godot_var2str(var); } - - public static WeakRef WeakRef(Object obj) - { - return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj)); - } } } diff --git a/modules/mono/glue/cs_files/ObjectExtensions.cs b/modules/mono/glue/cs_files/ObjectExtensions.cs new file mode 100644 index 0000000000..5c9e6609f4 --- /dev/null +++ b/modules/mono/glue/cs_files/ObjectExtensions.cs @@ -0,0 +1,17 @@ +using System; + +namespace Godot +{ + public partial class Object + { + public static bool IsInstanceValid(Object instance) + { + return instance != null && instance.NativeInstance != IntPtr.Zero; + } + + public static WeakRef WeakRef(Object obj) + { + return NativeCalls.godot_icall_Godot_weakref(Object.GetPtr(obj)); + } + } +} diff --git a/modules/mono/glue/cs_files/ResourceLoaderExtensions.cs b/modules/mono/glue/cs_files/ResourceLoaderExtensions.cs new file mode 100644 index 0000000000..ceecc589e6 --- /dev/null +++ b/modules/mono/glue/cs_files/ResourceLoaderExtensions.cs @@ -0,0 +1,10 @@ +namespace Godot +{ + public static partial class ResourceLoader + { + public static T Load<T>(string path) where T : Godot.Resource + { + return (T) Load(path); + } + } +} diff --git a/modules/mono/glue/cs_files/Transform.cs b/modules/mono/glue/cs_files/Transform.cs index d1b247a552..e432d5b52c 100644 --- a/modules/mono/glue/cs_files/Transform.cs +++ b/modules/mono/glue/cs_files/Transform.cs @@ -102,7 +102,18 @@ namespace Godot basis[0, 2] * vInv.x + basis[1, 2] * vInv.y + basis[2, 2] * vInv.z ); } - + + // Constants + private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero); + private static readonly Transform _flipX = new Transform(new Basis(new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1)), Vector3.Zero); + private static readonly Transform _flipY = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1)), Vector3.Zero); + private static readonly Transform _flipZ = new Transform(new Basis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, -1)), Vector3.Zero); + + public static Transform Identity { get { return _identity; } } + public static Transform FlipX { get { return _flipX; } } + public static Transform FlipY { get { return _flipY; } } + public static Transform FlipZ { get { return _flipZ; } } + // Constructors public Transform(Vector3 xAxis, Vector3 yAxis, Vector3 zAxis, Vector3 origin) { diff --git a/modules/mono/glue/cs_files/Transform2D.cs b/modules/mono/glue/cs_files/Transform2D.cs index ff5259178b..8d30833066 100644 --- a/modules/mono/glue/cs_files/Transform2D.cs +++ b/modules/mono/glue/cs_files/Transform2D.cs @@ -11,22 +11,10 @@ namespace Godot [StructLayout(LayoutKind.Sequential)] public struct Transform2D : IEquatable<Transform2D> { - private static readonly Transform2D identity = new Transform2D - ( - new Vector2(1f, 0f), - new Vector2(0f, 1f), - new Vector2(0f, 0f) - ); - public Vector2 x; public Vector2 y; public Vector2 o; - public static Transform2D Identity - { - get { return identity; } - } - public Vector2 Origin { get { return o; } @@ -264,6 +252,15 @@ namespace Godot Vector2 vInv = v - o; return new Vector2(x.Dot(vInv), y.Dot(vInv)); } + + // Constants + private static readonly Transform2D _identity = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, 1f), Vector2.Zero); + private static readonly Transform2D _flipX = new Transform2D(new Vector2(-1f, 0f), new Vector2(0f, 1f), Vector2.Zero); + private static readonly Transform2D _flipY = new Transform2D(new Vector2(1f, 0f), new Vector2(0f, -1f), Vector2.Zero); + + public static Transform2D Identity { get { return _identity; } } + public static Transform2D FlipX { get { return _flipX; } } + public static Transform2D FlipY { get { return _flipY; } } // Constructors public Transform2D(Vector2 xAxis, Vector2 yAxis, Vector2 origin) diff --git a/modules/mono/glue/cs_files/VERSION.txt b/modules/mono/glue/cs_files/VERSION.txt index 7f8f011eb7..ec635144f6 100755 --- a/modules/mono/glue/cs_files/VERSION.txt +++ b/modules/mono/glue/cs_files/VERSION.txt @@ -1 +1 @@ -7 +9 diff --git a/modules/mono/glue/cs_files/Vector2.cs b/modules/mono/glue/cs_files/Vector2.cs index c274364895..14c8de6986 100644 --- a/modules/mono/glue/cs_files/Vector2.cs +++ b/modules/mono/glue/cs_files/Vector2.cs @@ -231,24 +231,27 @@ namespace Godot { return new Vector2(y, -x); } - - private static readonly Vector2 zero = new Vector2 (0, 0); - private static readonly Vector2 one = new Vector2 (1, 1); - private static readonly Vector2 negOne = new Vector2 (-1, -1); - - private static readonly Vector2 up = new Vector2 (0, 1); - private static readonly Vector2 down = new Vector2 (0, -1); - private static readonly Vector2 right = new Vector2 (1, 0); - private static readonly Vector2 left = new Vector2 (-1, 0); - - public static Vector2 Zero { get { return zero; } } - public static Vector2 One { get { return one; } } - public static Vector2 NegOne { get { return negOne; } } - - public static Vector2 Up { get { return up; } } - public static Vector2 Down { get { return down; } } - public static Vector2 Right { get { return right; } } - public static Vector2 Left { get { return left; } } + + // Constants + private static readonly Vector2 _zero = new Vector2(0, 0); + private static readonly Vector2 _one = new Vector2(1, 1); + private static readonly Vector2 _negOne = new Vector2(-1, -1); + private static readonly Vector2 _inf = new Vector2(Mathf.Inf, Mathf.Inf); + + private static readonly Vector2 _up = new Vector2(0, -1); + private static readonly Vector2 _down = new Vector2(0, 1); + private static readonly Vector2 _right = new Vector2(1, 0); + private static readonly Vector2 _left = new Vector2(-1, 0); + + public static Vector2 Zero { get { return _zero; } } + public static Vector2 NegOne { get { return _negOne; } } + public static Vector2 One { get { return _one; } } + public static Vector2 Inf { get { return _inf; } } + + public static Vector2 Up { get { return _up; } } + public static Vector2 Down { get { return _down; } } + public static Vector2 Right { get { return _right; } } + public static Vector2 Left { get { return _left; } } // Constructors public Vector2(real_t x, real_t y) diff --git a/modules/mono/glue/cs_files/Vector3.cs b/modules/mono/glue/cs_files/Vector3.cs index 085a4f0043..861d9c54d9 100644 --- a/modules/mono/glue/cs_files/Vector3.cs +++ b/modules/mono/glue/cs_files/Vector3.cs @@ -272,27 +272,30 @@ namespace Godot ); } - private static readonly Vector3 zero = new Vector3 (0, 0, 0); - private static readonly Vector3 one = new Vector3 (1, 1, 1); - private static readonly Vector3 negOne = new Vector3 (-1, -1, -1); + // Constants + private static readonly Vector3 _zero = new Vector3(0, 0, 0); + private static readonly Vector3 _one = new Vector3(1, 1, 1); + private static readonly Vector3 _negOne = new Vector3(-1, -1, -1); + private static readonly Vector3 _inf = new Vector3(Mathf.Inf, Mathf.Inf, Mathf.Inf); - private static readonly Vector3 up = new Vector3 (0, 1, 0); - private static readonly Vector3 down = new Vector3 (0, -1, 0); - private static readonly Vector3 right = new Vector3 (1, 0, 0); - private static readonly Vector3 left = new Vector3 (-1, 0, 0); - private static readonly Vector3 forward = new Vector3 (0, 0, -1); - private static readonly Vector3 back = new Vector3 (0, 0, 1); - - public static Vector3 Zero { get { return zero; } } - public static Vector3 One { get { return one; } } - public static Vector3 NegOne { get { return negOne; } } + private static readonly Vector3 _up = new Vector3(0, 1, 0); + private static readonly Vector3 _down = new Vector3(0, -1, 0); + private static readonly Vector3 _right = new Vector3(1, 0, 0); + private static readonly Vector3 _left = new Vector3(-1, 0, 0); + private static readonly Vector3 _forward = new Vector3(0, 0, -1); + private static readonly Vector3 _back = new Vector3(0, 0, 1); + + public static Vector3 Zero { get { return _zero; } } + public static Vector3 One { get { return _one; } } + public static Vector3 NegOne { get { return _negOne; } } + public static Vector3 Inf { get { return _inf; } } - public static Vector3 Up { get { return up; } } - public static Vector3 Down { get { return down; } } - public static Vector3 Right { get { return right; } } - public static Vector3 Left { get { return left; } } - public static Vector3 Forward { get { return forward; } } - public static Vector3 Back { get { return back; } } + public static Vector3 Up { get { return _up; } } + public static Vector3 Down { get { return _down; } } + public static Vector3 Right { get { return _right; } } + public static Vector3 Left { get { return _left; } } + public static Vector3 Forward { get { return _forward; } } + public static Vector3 Back { get { return _back; } } // Constructors public Vector3(real_t x, real_t y, real_t z) diff --git a/modules/mono/utils/thread_local.cpp b/modules/mono/utils/thread_local.cpp index 248f24c855..ae9f130518 100644 --- a/modules/mono/utils/thread_local.cpp +++ b/modules/mono/utils/thread_local.cpp @@ -69,7 +69,7 @@ struct ThreadLocalStorage::Impl { #define _CALLBACK_FUNC_ #endif - Impl(void _CALLBACK_FUNC_ (*p_destr_callback_func)(void *)) { + Impl(void (_CALLBACK_FUNC_ *p_destr_callback_func)(void *)) { #ifdef WINDOWS_ENABLED dwFlsIndex = FlsAlloc(p_destr_callback_func); ERR_FAIL_COND(dwFlsIndex == FLS_OUT_OF_INDEXES); @@ -95,7 +95,7 @@ void ThreadLocalStorage::set_value(void *p_value) const { pimpl->set_value(p_value); } -void ThreadLocalStorage::alloc(void _CALLBACK_FUNC_ (*p_destr_callback)(void *)) { +void ThreadLocalStorage::alloc(void (_CALLBACK_FUNC_ *p_destr_callback)(void *)) { pimpl = memnew(ThreadLocalStorage::Impl(p_destr_callback)); } diff --git a/modules/mono/utils/thread_local.h b/modules/mono/utils/thread_local.h index d0c5df3c91..783e40dc01 100644 --- a/modules/mono/utils/thread_local.h +++ b/modules/mono/utils/thread_local.h @@ -76,7 +76,7 @@ struct ThreadLocalStorage { void *get_value() const; void set_value(void *p_value) const; - void alloc(void _CALLBACK_FUNC_ (*p_dest_callback)(void *)); + void alloc(void (_CALLBACK_FUNC_ *p_dest_callback)(void *)); void free(); private: diff --git a/modules/squish/image_compress_squish.cpp b/modules/squish/image_compress_squish.cpp index 0cf24dd8d8..f6be537413 100644 --- a/modules/squish/image_compress_squish.cpp +++ b/modules/squish/image_compress_squish.cpp @@ -46,7 +46,7 @@ void image_decompress_squish(Image *p_image) { Image::Format target_format = Image::FORMAT_RGBA8; PoolVector<uint8_t> data; - int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0); + int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); int mm_count = p_image->get_mipmap_count(); data.resize(target_size); @@ -96,6 +96,33 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) { Image::DetectChannels dc = p_image->get_detected_channels(); + if (p_source == Image::COMPRESS_SOURCE_LAYERED) { + //keep what comes in + switch (p_image->get_format()) { + case Image::FORMAT_L8: { + dc = Image::DETECTED_L; + } break; + case Image::FORMAT_LA8: { + dc = Image::DETECTED_LA; + } break; + case Image::FORMAT_R8: { + dc = Image::DETECTED_R; + } break; + case Image::FORMAT_RG8: { + dc = Image::DETECTED_RG; + } break; + case Image::FORMAT_RGB8: { + dc = Image::DETECTED_RGB; + } break; + case Image::FORMAT_RGBA8: + case Image::FORMAT_RGBA4444: + case Image::FORMAT_RGBA5551: { + dc = Image::DETECTED_RGBA; + } break; + default: {} + } + } + p_image->convert(Image::FORMAT_RGBA8); //still uses RGBA to convert if (p_source == Image::COMPRESS_SOURCE_SRGB && (dc == Image::DETECTED_R || dc == Image::DETECTED_RG)) { @@ -148,7 +175,7 @@ void image_compress_squish(Image *p_image, Image::CompressSource p_source) { } PoolVector<uint8_t> data; - int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps() ? -1 : 0); + int target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0; data.resize(target_size); int shift = Image::get_format_pixel_rshift(target_format); diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index de9b3d5a91..bbdec7195f 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -2415,7 +2415,7 @@ void VisualScriptLanguage::make_template(const String &p_class_name, const Strin script->set_instance_base_type(p_base_class_name); } -bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, Set<int> *r_safe_lines) const { +bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { return false; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index 2ad72a40c0..13a8b909b0 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -564,7 +564,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, Set<int> *r_safe_lines = NULL) const; + virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = NULL, List<ScriptLanguage::Warning> *r_warnings = NULL, Set<int> *r_safe_lines = NULL) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index ef40af686c..45a27d1e79 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -3032,7 +3032,8 @@ void VisualScriptEditor::_node_filter_changed(const String &p_text) { void VisualScriptEditor::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { - node_filter->add_icon_override("right_icon", Control::get_icon("Search", "EditorIcons")); + node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons")); + node_filter->set_clear_button_enabled(true); variable_editor->connect("changed", this, "_update_members"); signal_editor->connect("changed", this, "_update_members"); diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index a6ec36d364..d499512d93 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -1663,7 +1663,7 @@ Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const { class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance { public: - int value; + Variant value; bool valid; //virtual int get_working_memory_size() const { return 0; } @@ -1682,7 +1682,7 @@ public: VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instance(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant); - instance->value = Variant::get_numeric_constant_value(type, name, &instance->valid); + instance->value = Variant::get_constant_value(type, name, &instance->valid); return instance; } @@ -1691,7 +1691,7 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) c if (property.name == "constant") { List<StringName> constants; - Variant::get_numeric_constants_for_type(type, &constants); + Variant::get_constants_for_type(type, &constants); if (constants.size() == 0) { property.usage = 0; diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub index 15a88773e7..c0985b3245 100644 --- a/modules/websocket/SCsub +++ b/modules/websocket/SCsub @@ -7,87 +7,88 @@ Import('env_modules') env_lws = env_modules.Clone() -thirdparty_dir = "#thirdparty/libwebsockets/" -helper_dir = "win32helpers/" -thirdparty_sources = [ - - "core/alloc.c", - "core/context.c", - "core/libwebsockets.c", - "core/output.c", - "core/pollfd.c", - "core/service.c", - - "event-libs/poll/poll.c", - - "misc/base64-decode.c", - "misc/lejp.c", - "misc/sha-1.c", - - "roles/h1/ops-h1.c", - "roles/http/header.c", - "roles/http/client/client.c", - "roles/http/client/client-handshake.c", - "roles/http/server/fops-zip.c", - "roles/http/server/lejp-conf.c", - "roles/http/server/parsers.c", - "roles/http/server/server.c", - "roles/listen/ops-listen.c", - "roles/pipe/ops-pipe.c", - "roles/raw/ops-raw.c", - - "roles/ws/client-ws.c", - "roles/ws/client-parser-ws.c", - "roles/ws/ops-ws.c", - "roles/ws/server-ws.c", - - "tls/tls.c", - "tls/tls-client.c", - "tls/tls-server.c", - - "tls/mbedtls/wrapper/library/ssl_cert.c", - "tls/mbedtls/wrapper/library/ssl_pkey.c", - "tls/mbedtls/wrapper/library/ssl_stack.c", - "tls/mbedtls/wrapper/library/ssl_methods.c", - "tls/mbedtls/wrapper/library/ssl_lib.c", - "tls/mbedtls/wrapper/library/ssl_x509.c", - "tls/mbedtls/wrapper/platform/ssl_port.c", - "tls/mbedtls/wrapper/platform/ssl_pm.c", - "tls/mbedtls/lws-genhash.c", - "tls/mbedtls/mbedtls-client.c", - "tls/mbedtls/lws-genrsa.c", - "tls/mbedtls/ssl.c", - "tls/mbedtls/mbedtls-server.c" -] - -if env_lws["platform"] == "android": # Builtin getifaddrs - thirdparty_sources += ["misc/getifaddrs.c"] - -if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock - thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"] -else: # Unix socket - thirdparty_sources += ["plat/lws-plat-unix.c"] - - -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -if env_lws["platform"] == "javascript": # No need to add third party libraries at all - pass -else: - env_lws.add_source_files(env.modules_sources, thirdparty_sources) - env_lws.Append(CPPPATH=[thirdparty_dir]) - - wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] - env_lws.Prepend(CPPPATH=wrapper_includes) - - if env['builtin_mbedtls']: - mbedtls_includes = "#thirdparty/mbedtls/include" - env_lws.Prepend(CPPPATH=[mbedtls_includes]) - - if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": - env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir]) - - if env_lws["platform"] == "uwp": - env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"]) +if env['builtin_libwebsockets']: + thirdparty_dir = "#thirdparty/libwebsockets/" + helper_dir = "win32helpers/" + thirdparty_sources = [ + + "core/alloc.c", + "core/context.c", + "core/libwebsockets.c", + "core/output.c", + "core/pollfd.c", + "core/service.c", + + "event-libs/poll/poll.c", + + "misc/base64-decode.c", + "misc/lejp.c", + "misc/sha-1.c", + + "roles/h1/ops-h1.c", + "roles/http/header.c", + "roles/http/client/client.c", + "roles/http/client/client-handshake.c", + "roles/http/server/fops-zip.c", + "roles/http/server/lejp-conf.c", + "roles/http/server/parsers.c", + "roles/http/server/server.c", + "roles/listen/ops-listen.c", + "roles/pipe/ops-pipe.c", + "roles/raw/ops-raw.c", + + "roles/ws/client-ws.c", + "roles/ws/client-parser-ws.c", + "roles/ws/ops-ws.c", + "roles/ws/server-ws.c", + + "tls/tls.c", + "tls/tls-client.c", + "tls/tls-server.c", + + "tls/mbedtls/wrapper/library/ssl_cert.c", + "tls/mbedtls/wrapper/library/ssl_pkey.c", + "tls/mbedtls/wrapper/library/ssl_stack.c", + "tls/mbedtls/wrapper/library/ssl_methods.c", + "tls/mbedtls/wrapper/library/ssl_lib.c", + "tls/mbedtls/wrapper/library/ssl_x509.c", + "tls/mbedtls/wrapper/platform/ssl_port.c", + "tls/mbedtls/wrapper/platform/ssl_pm.c", + "tls/mbedtls/lws-genhash.c", + "tls/mbedtls/mbedtls-client.c", + "tls/mbedtls/lws-genrsa.c", + "tls/mbedtls/ssl.c", + "tls/mbedtls/mbedtls-server.c" + ] + + if env_lws["platform"] == "android": # Builtin getifaddrs + thirdparty_sources += ["misc/getifaddrs.c"] + + if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": # Winsock + thirdparty_sources += ["plat/lws-plat-win.c", helper_dir + "getopt.c", helper_dir + "getopt_long.c", helper_dir + "gettimeofday.c"] + else: # Unix socket + thirdparty_sources += ["plat/lws-plat-unix.c"] + + + thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] + + if env_lws["platform"] == "javascript": # No need to add third party libraries at all + pass + else: + env_lws.add_source_files(env.modules_sources, thirdparty_sources) + env_lws.Append(CPPPATH=[thirdparty_dir]) + + wrapper_includes = ["#thirdparty/libwebsockets/tls/mbedtls/wrapper/include/" + inc for inc in ["internal", "openssl", "platform", ""]] + env_lws.Prepend(CPPPATH=wrapper_includes) + + if env['builtin_mbedtls']: + mbedtls_includes = "#thirdparty/mbedtls/include" + env_lws.Prepend(CPPPATH=[mbedtls_includes]) + + if env_lws["platform"] == "windows" or env_lws["platform"] == "uwp": + env_lws.Append(CPPPATH=[thirdparty_dir + helper_dir]) + + if env_lws["platform"] == "uwp": + env_lws.Append(CCFLAGS=["/DLWS_MINGW_SUPPORT"]) env_lws.add_source_files(env.modules_sources, "*.cpp") diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp index 06f97aaf05..ac31daa108 100644 --- a/modules/websocket/lws_client.cpp +++ b/modules/websocket/lws_client.cpp @@ -127,11 +127,6 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi case LWS_CALLBACK_CLIENT_ESTABLISHED: peer->set_wsi(wsi); peer_data->peer_id = 0; - peer_data->in_size = 0; - peer_data->in_count = 0; - peer_data->out_count = 0; - peer_data->rbw.resize(16); - peer_data->rbr.resize(16); peer_data->force_close = false; _on_connect(lws_get_protocol(wsi)->name); break; @@ -142,10 +137,6 @@ int LWSClient::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi return -1; // we should close the connection (would probably happen anyway) case LWS_CALLBACK_CLIENT_CLOSED: - peer_data->in_count = 0; - peer_data->out_count = 0; - peer_data->rbw.resize(0); - peer_data->rbr.resize(0); peer->close(); destroy_context(); _on_disconnect(); diff --git a/modules/websocket/lws_peer.cpp b/modules/websocket/lws_peer.cpp index 96acb99cc4..0989357258 100644 --- a/modules/websocket/lws_peer.cpp +++ b/modules/websocket/lws_peer.cpp @@ -41,6 +41,10 @@ #include "drivers/unix/socket_helpers.h" void LWSPeer::set_wsi(struct lws *p_wsi) { + ERR_FAIL_COND(wsi != NULL); + + rbw.resize(16); + rbr.resize(16); wsi = p_wsi; }; @@ -57,24 +61,24 @@ Error LWSPeer::read_wsi(void *in, size_t len) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi)); - uint32_t size = peer_data->in_size; + uint32_t size = in_size; uint8_t is_string = lws_frame_is_binary(wsi) ? 0 : 1; - if (peer_data->rbr.space_left() < len + 5) { + if (rbr.space_left() < len + 5) { ERR_EXPLAIN("Buffer full! Dropping data"); ERR_FAIL_V(FAILED); } - copymem(&(peer_data->input_buffer[size]), in, len); + copymem(&(input_buffer[size]), in, len); size += len; - peer_data->in_size = size; + in_size = size; if (lws_is_final_fragment(wsi)) { - peer_data->rbr.write((uint8_t *)&size, 4); - peer_data->rbr.write((uint8_t *)&is_string, 1); - peer_data->rbr.write(peer_data->input_buffer, size); - peer_data->in_count++; - peer_data->in_size = 0; + rbr.write((uint8_t *)&size, 4); + rbr.write((uint8_t *)&is_string, 1); + rbr.write(input_buffer, size); + in_count++; + in_size = 0; } return OK; @@ -86,26 +90,26 @@ Error LWSPeer::write_wsi() { PeerData *peer_data = (PeerData *)(lws_wsi_user(wsi)); PoolVector<uint8_t> tmp; - int left = peer_data->rbw.data_left(); + int left = rbw.data_left(); uint32_t to_write = 0; - if (left == 0 || peer_data->out_count == 0) + if (left == 0 || out_count == 0) return OK; - peer_data->rbw.read((uint8_t *)&to_write, 4); - peer_data->out_count--; + rbw.read((uint8_t *)&to_write, 4); + out_count--; if (left < to_write) { - peer_data->rbw.advance_read(left); + rbw.advance_read(left); return FAILED; } tmp.resize(LWS_PRE + to_write); - peer_data->rbw.read(&(tmp.write()[LWS_PRE]), to_write); + rbw.read(&(tmp.write()[LWS_PRE]), to_write); lws_write(wsi, &(tmp.write()[LWS_PRE]), to_write, (enum lws_write_protocol)write_mode); tmp.resize(0); - if (peer_data->out_count > 0) + if (out_count > 0) lws_callback_on_writable(wsi); // we want to write more! return OK; @@ -116,9 +120,9 @@ Error LWSPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(!is_connected_to_host(), FAILED); PeerData *peer_data = (PeerData *)lws_wsi_user(wsi); - peer_data->rbw.write((uint8_t *)&p_buffer_size, 4); - peer_data->rbw.write(p_buffer, MIN(p_buffer_size, peer_data->rbw.space_left())); - peer_data->out_count++; + rbw.write((uint8_t *)&p_buffer_size, 4); + rbw.write(p_buffer, MIN(p_buffer_size, rbw.space_left())); + out_count++; lws_callback_on_writable(wsi); // notify that we want to write return OK; @@ -130,7 +134,7 @@ Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { PeerData *peer_data = (PeerData *)lws_wsi_user(wsi); - if (peer_data->in_count == 0) + if (in_count == 0) return ERR_UNAVAILABLE; uint32_t to_read = 0; @@ -138,17 +142,17 @@ Error LWSPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { uint8_t is_string = 0; r_buffer_size = 0; - peer_data->rbr.read((uint8_t *)&to_read, 4); - peer_data->in_count--; - left = peer_data->rbr.data_left(); + rbr.read((uint8_t *)&to_read, 4); + in_count--; + left = rbr.data_left(); if (left < to_read + 1) { - peer_data->rbr.advance_read(left); + rbr.advance_read(left); return FAILED; } - peer_data->rbr.read(&is_string, 1); - peer_data->rbr.read(packet_buffer, to_read); + rbr.read(&is_string, 1); + rbr.read(packet_buffer, to_read); *r_buffer = packet_buffer; r_buffer_size = to_read; _was_string = is_string; @@ -161,7 +165,7 @@ int LWSPeer::get_available_packet_count() const { if (!is_connected_to_host()) return 0; - return ((PeerData *)lws_wsi_user(wsi))->in_count; + return in_count; }; bool LWSPeer::was_string_packet() const { @@ -176,12 +180,17 @@ bool LWSPeer::is_connected_to_host() const { void LWSPeer::close() { if (wsi != NULL) { - struct lws *tmp = wsi; PeerData *data = ((PeerData *)lws_wsi_user(wsi)); data->force_close = true; - wsi = NULL; - lws_callback_on_writable(tmp); // notify that we want to disconnect + lws_callback_on_writable(wsi); // notify that we want to disconnect } + wsi = NULL; + rbw.resize(0); + rbr.resize(0); + in_count = 0; + in_size = 0; + out_count = 0; + _was_string = false; }; IP_Address LWSPeer::get_connected_host() const { @@ -228,8 +237,8 @@ uint16_t LWSPeer::get_connected_port() const { LWSPeer::LWSPeer() { wsi = NULL; - _was_string = false; write_mode = WRITE_MODE_BINARY; + close(); }; LWSPeer::~LWSPeer() { diff --git a/modules/websocket/lws_peer.h b/modules/websocket/lws_peer.h index e96b38b168..d7d46e3076 100644 --- a/modules/websocket/lws_peer.h +++ b/modules/websocket/lws_peer.h @@ -57,14 +57,15 @@ public: struct PeerData { uint32_t peer_id; bool force_close; - RingBuffer<uint8_t> rbw; - RingBuffer<uint8_t> rbr; - mutable uint8_t input_buffer[PACKET_BUFFER_SIZE]; - uint32_t in_size; - int in_count; - int out_count; }; + RingBuffer<uint8_t> rbw; + RingBuffer<uint8_t> rbr; + uint8_t input_buffer[PACKET_BUFFER_SIZE]; + uint32_t in_size; + int in_count; + int out_count; + virtual int get_available_packet_count() const; virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); diff --git a/modules/websocket/lws_server.cpp b/modules/websocket/lws_server.cpp index 8d13dc7a98..bb724bce9c 100644 --- a/modules/websocket/lws_server.cpp +++ b/modules/websocket/lws_server.cpp @@ -92,11 +92,6 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi _peer_map[id] = peer; peer_data->peer_id = id; - peer_data->in_size = 0; - peer_data->in_count = 0; - peer_data->out_count = 0; - peer_data->rbw.resize(16); - peer_data->rbr.resize(16); peer_data->force_close = false; _on_connect(id, lws_get_protocol(wsi)->name); @@ -111,10 +106,6 @@ int LWSServer::_handle_cb(struct lws *wsi, enum lws_callback_reasons reason, voi _peer_map[id]->close(); _peer_map.erase(id); } - peer_data->in_count = 0; - peer_data->out_count = 0; - peer_data->rbr.resize(0); - peer_data->rbw.resize(0); _on_disconnect(id); return 0; // we can end here } diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp index 1f901c4919..aeaf698015 100644 --- a/platform/haiku/audio_driver_media_kit.cpp +++ b/platform/haiku/audio_driver_media_kit.cpp @@ -100,7 +100,7 @@ int AudioDriverMediaKit::get_mix_rate() const { return mix_rate; } -AudioDriverSW::SpeakerMode AudioDriverMediaKit::get_speaker_mode() const { +AudioDriverMediaKit::SpeakerMode AudioDriverMediaKit::get_speaker_mode() const { return speaker_mode; } diff --git a/platform/haiku/audio_driver_media_kit.h b/platform/haiku/audio_driver_media_kit.h index a09403e7d6..02fefcf52a 100644 --- a/platform/haiku/audio_driver_media_kit.h +++ b/platform/haiku/audio_driver_media_kit.h @@ -35,9 +35,10 @@ #include "core/os/mutex.h" #include "core/os/thread.h" -#include <SoundPlayer.h> #include <kernel/image.h> // needed for image_id +#include <SoundPlayer.h> + class AudioDriverMediaKit : public AudioDriver { Mutex *mutex; diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py index 2959023204..7ecdd2bb11 100644 --- a/platform/haiku/detect.py +++ b/platform/haiku/detect.py @@ -64,6 +64,87 @@ def configure(env): env["CC"] = "gcc-x86" env["CXX"] = "g++-x86" + ## Dependencies + + if not env['builtin_libwebp']: + env.ParseConfig('pkg-config libwebp --cflags --libs') + + # freetype depends on libpng and zlib, so bundling one of them while keeping others + # as shared libraries leads to weird issues + if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']: + env['builtin_freetype'] = True + env['builtin_libpng'] = True + env['builtin_zlib'] = True + + if not env['builtin_freetype']: + env.ParseConfig('pkg-config freetype2 --cflags --libs') + + if not env['builtin_libpng']: + env.ParseConfig('pkg-config libpng --cflags --libs') + + if not env['builtin_bullet']: + # We need at least version 2.88 + import subprocess + bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip() + if bullet_version < "2.88": + # Abort as system bullet was requested but too old + print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88")) + sys.exit(255) + env.ParseConfig('pkg-config bullet --cflags --libs') + + if not env['builtin_enet']: + env.ParseConfig('pkg-config libenet --cflags --libs') + + if not env['builtin_squish'] and env['tools']: + env.ParseConfig('pkg-config libsquish --cflags --libs') + + if not env['builtin_zstd']: + env.ParseConfig('pkg-config libzstd --cflags --libs') + + # Sound and video libraries + # Keep the order as it triggers chained dependencies (ogg needed by others, etc.) + + if not env['builtin_libtheora']: + env['builtin_libogg'] = False # Needed to link against system libtheora + env['builtin_libvorbis'] = False # Needed to link against system libtheora + env.ParseConfig('pkg-config theora theoradec --cflags --libs') + + if not env['builtin_libvpx']: + env.ParseConfig('pkg-config vpx --cflags --libs') + + if not env['builtin_libvorbis']: + env['builtin_libogg'] = False # Needed to link against system libvorbis + env.ParseConfig('pkg-config vorbis vorbisfile --cflags --libs') + + if not env['builtin_opus']: + env['builtin_libogg'] = False # Needed to link against system opus + env.ParseConfig('pkg-config opus opusfile --cflags --libs') + + if not env['builtin_libogg']: + env.ParseConfig('pkg-config ogg --cflags --libs') + + if env['builtin_libtheora']: + list_of_x86 = ['x86_64', 'x86', 'i386', 'i586'] + if any(platform.machine() in s for s in list_of_x86): + env["x86_libtheora_opt_gcc"] = True + + if not env['builtin_libwebsockets']: + env.ParseConfig('pkg-config libwebsockets --cflags --libs') + + if not env['builtin_mbedtls']: + # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228 + env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509']) + + if not env['builtin_miniupnpc']: + # No pkgconfig file so far, hardcode default paths. + env.Append(CPPPATH=["/system/develop/headers/x86/miniupnpc"]) + env.Append(LIBS=["miniupnpc"]) + + # On Linux wchar_t should be 32-bits + # 16-bit library shouldn't be required due to compiler optimisations + if not env['builtin_pcre2']: + env.ParseConfig('pkg-config libpcre2-32 --cflags --libs') + ## Flags env.Append(CPPPATH=['#platform/haiku']) diff --git a/platform/haiku/haiku_application.h b/platform/haiku/haiku_application.h index f92969bbb1..a870037985 100644 --- a/platform/haiku/haiku_application.h +++ b/platform/haiku/haiku_application.h @@ -31,9 +31,10 @@ #ifndef HAIKU_APPLICATION_H #define HAIKU_APPLICATION_H -#include <Application.h> #include <kernel/image.h> // needed for image_id +#include <Application.h> + class HaikuApplication : public BApplication { public: HaikuApplication(); diff --git a/platform/haiku/haiku_direct_window.cpp b/platform/haiku/haiku_direct_window.cpp index b234a2ff91..7eeb226167 100644 --- a/platform/haiku/haiku_direct_window.cpp +++ b/platform/haiku/haiku_direct_window.cpp @@ -41,10 +41,14 @@ HaikuDirectWindow::HaikuDirectWindow(BRect p_frame) : last_buttons_state = 0; last_button_mask = 0; last_key_modifier_state = 0; + + view = NULL; + update_runner = NULL; + input = NULL; + main_loop = NULL; } HaikuDirectWindow::~HaikuDirectWindow() { - delete update_runner; } void HaikuDirectWindow::SetHaikuGLView(HaikuGLView *p_view) { @@ -53,7 +57,7 @@ void HaikuDirectWindow::SetHaikuGLView(HaikuGLView *p_view) { void HaikuDirectWindow::StartMessageRunner() { update_runner = new BMessageRunner(BMessenger(this), - new BMessage(REDRAW_MSG), 1000000 / 30 /* 30 fps */); + new BMessage(REDRAW_MSG), 1000000 / 60 /* 60 fps */); } void HaikuDirectWindow::StopMessageRunner() { @@ -69,6 +73,7 @@ void HaikuDirectWindow::SetMainLoop(MainLoop *p_main_loop) { } bool HaikuDirectWindow::QuitRequested() { + StopMessageRunner(); main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST); return false; } @@ -152,39 +157,36 @@ void HaikuDirectWindow::HandleMouseButton(BMessage *message) { } */ - Ref<InputEvent> mouse_event; - mouse_event.type = Ref<InputEvent>::MOUSE_BUTTON; - mouse_event.device = 0; + Ref<InputEventMouseButton> mouse_event; + mouse_event.instance(); - mouse_event.mouse_button.mod = GetKeyModifierState(modifiers); - mouse_event->get_button_mask() = GetMouseButtonState(buttons); - mouse_event->get_position().x = where.x; - mouse_event->get_position().y = where.y; - mouse_event.mouse_button.global_x = where.x; - mouse_event.mouse_button.global_y = where.y; + mouse_event->set_button_mask(GetMouseButtonState(buttons)); + mouse_event->set_position({ where.x, where.y }); + mouse_event->set_global_position({ where.x, where.y }); + GetKeyModifierState(mouse_event, modifiers); switch (button) { default: case B_PRIMARY_MOUSE_BUTTON: - mouse_event->get_button_index() = 1; + mouse_event->set_button_index(1); break; case B_SECONDARY_MOUSE_BUTTON: - mouse_event->get_button_index() = 2; + mouse_event->set_button_index(2); break; case B_TERTIARY_MOUSE_BUTTON: - mouse_event->get_button_index() = 3; + mouse_event->set_button_index(3); break; } - mouse_event->is_pressed() = (message->what == B_MOUSE_DOWN); + mouse_event->set_pressed(message->what == B_MOUSE_DOWN); if (message->what == B_MOUSE_DOWN && mouse_event->get_button_index() == 1) { int32 clicks = message->FindInt32("clicks"); if (clicks > 1) { - mouse_event.mouse_button.doubleclick = true; + mouse_event->set_doubleclick(true); } } @@ -208,22 +210,18 @@ void HaikuDirectWindow::HandleMouseMoved(BMessage *message) { Point2i rel = pos - last_mouse_position; - Ref<InputEvent> motion_event; - motion_event.type = Ref<InputEvent>::MOUSE_MOTION; - motion_event.device = 0; + Ref<InputEventMouseMotion> motion_event; + motion_event.instance(); + GetKeyModifierState(motion_event, modifiers); - motion_event.mouse_motion.mod = GetKeyModifierState(modifiers); - motion_event->get_button_mask() = GetMouseButtonState(buttons); - motion_event.mouse_motion.x = pos.x; - motion_event.mouse_motion.y = pos.y; + motion_event->set_button_mask(GetMouseButtonState(buttons)); + motion_event->set_position({ pos.x, pos.y }); input->set_mouse_position(pos); - motion_event.mouse_motion.global_x = pos.x; - motion_event.mouse_motion.global_y = pos.y; - motion_event.mouse_motion.speed_x = input->get_last_mouse_speed().x; - motion_event.mouse_motion.speed_y = input->get_last_mouse_speed().y; + motion_event->set_global_position({ pos.x, pos.y }); + motion_event->set_speed({ input->get_last_mouse_speed().x, + input->get_last_mouse_speed().y }); - motion_event->get_relative().x = rel.x; - motion_event->get_relative().y = rel.y; + motion_event->set_relative({ rel.x, rel.y }); last_mouse_position = pos; @@ -236,22 +234,21 @@ void HaikuDirectWindow::HandleMouseWheelChanged(BMessage *message) { return; } - Ref<InputEvent> mouse_event; - mouse_event.type = Ref<InputEvent>::MOUSE_BUTTON; - mouse_event.device = 0; + Ref<InputEventMouseButton> mouse_event; + mouse_event.instance(); + //GetKeyModifierState(mouse_event, modifiers); - mouse_event->get_button_index() = wheel_delta_y < 0 ? 4 : 5; - mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state); - mouse_event->get_button_mask() = last_button_mask; - mouse_event->get_position().x = last_mouse_position.x; - mouse_event->get_position().y = last_mouse_position.y; - mouse_event.mouse_button.global_x = last_mouse_position.x; - mouse_event.mouse_button.global_y = last_mouse_position.y; + mouse_event->set_button_index(wheel_delta_y < 0 ? 4 : 5); + mouse_event->set_button_mask(last_button_mask); + mouse_event->set_position({ last_mouse_position.x, + last_mouse_position.y }); + mouse_event->set_global_position({ last_mouse_position.x, + last_mouse_position.y }); - mouse_event->is_pressed() = true; + mouse_event->set_pressed(true); input->parse_input_event(mouse_event); - mouse_event->is_pressed() = false; + mouse_event->set_pressed(false); input->parse_input_event(mouse_event); } @@ -272,24 +269,23 @@ void HaikuDirectWindow::HandleKeyboardEvent(BMessage *message) { return; } - Ref<InputEvent> event; - event.type = Ref<InputEvent>::KEY; - event.device = 0; - event.key.mod = GetKeyModifierState(modifiers); - event->is_pressed() = (message->what == B_KEY_DOWN); - event->get_scancode() = KeyMappingHaiku::get_keysym(raw_char, key); - event->is_echo() = message->HasInt32("be:key_repeat"); - event.key.unicode = 0; + Ref<InputEventKey> event; + event.instance(); + GetKeyModifierState(event, modifiers); + event->set_pressed(message->what == B_KEY_DOWN); + event->set_scancode(KeyMappingHaiku::get_keysym(raw_char, key)); + event->set_echo(message->HasInt32("be:key_repeat")); + event->set_unicode(0); const char *bytes = NULL; if (message->FindString("bytes", &bytes) == B_OK) { - event.key.unicode = BUnicodeChar::FromUTF8(&bytes); + event->set_unicode(BUnicodeChar::FromUTF8(&bytes)); } //make it consistent across platforms. if (event->get_scancode() == KEY_BACKTAB) { - event->get_scancode() = KEY_TAB; - event->get_shift() = true; + event->set_scancode(KEY_TAB); + event->set_shift(true); } input->parse_input_event(event); @@ -309,14 +305,14 @@ void HaikuDirectWindow::HandleKeyboardModifierEvent(BMessage *message) { int32 key = old_modifiers ^ modifiers; - Ref<InputEvent> event; - event.type = Ref<InputEvent>::KEY; - event.device = 0; - event.key.mod = GetKeyModifierState(modifiers); - event->is_pressed() = ((modifiers & key) != 0); - event->get_scancode() = KeyMappingHaiku::get_modifier_keysym(key); - event->is_echo() = false; - event.key.unicode = 0; + Ref<InputEventWithModifiers> event; + event.instance(); + GetKeyModifierState(event, modifiers); + + event->set_shift(key & B_SHIFT_KEY); + event->set_alt(key & B_OPTION_KEY); + event->set_control(key & B_CONTROL_KEY); + event->set_command(key & B_COMMAND_KEY); input->parse_input_event(event); } @@ -333,14 +329,13 @@ void HaikuDirectWindow::HandleWindowResized(BMessage *message) { current_video_mode->height = height; } -inline InputModifierState HaikuDirectWindow::GetKeyModifierState(uint32 p_state) { +inline void HaikuDirectWindow::GetKeyModifierState(Ref<InputEventWithModifiers> event, uint32 p_state) { last_key_modifier_state = p_state; - InputModifierState state; - state.shift = (p_state & B_SHIFT_KEY) != 0; - state.control = (p_state & B_CONTROL_KEY) != 0; - state.alt = (p_state & B_OPTION_KEY) != 0; - state.meta = (p_state & B_COMMAND_KEY) != 0; + event->set_shift(p_state & B_SHIFT_KEY); + event->set_control(p_state & B_CONTROL_KEY); + event->set_alt(p_state & B_OPTION_KEY); + event->set_metakey(p_state & B_COMMAND_KEY); return state; } diff --git a/platform/haiku/haiku_direct_window.h b/platform/haiku/haiku_direct_window.h index 55c2f5fccc..eee09191fa 100644 --- a/platform/haiku/haiku_direct_window.h +++ b/platform/haiku/haiku_direct_window.h @@ -31,9 +31,10 @@ #ifndef HAIKU_DIRECT_WINDOW_H #define HAIKU_DIRECT_WINDOW_H -#include <DirectWindow.h> #include <kernel/image.h> // needed for image_id +#include <DirectWindow.h> + #include "core/os/os.h" #include "main/input_default.h" @@ -63,7 +64,7 @@ private: void HandleWindowResized(BMessage *message); void HandleKeyboardEvent(BMessage *message); void HandleKeyboardModifierEvent(BMessage *message); - inline InputModifierState GetKeyModifierState(uint32 p_state); + inline void GetKeyModifierState(Ref<InputEventWithModifiers> event, uint32 p_state); inline int GetMouseButtonState(uint32 p_state); public: diff --git a/platform/haiku/haiku_gl_view.h b/platform/haiku/haiku_gl_view.h index 1a694dc13b..6869cb7de7 100644 --- a/platform/haiku/haiku_gl_view.h +++ b/platform/haiku/haiku_gl_view.h @@ -31,9 +31,10 @@ #ifndef HAIKU_GL_VIEW_H #define HAIKU_GL_VIEW_H -#include <GLView.h> #include <kernel/image.h> // needed for image_id +#include <GLView.h> + class HaikuGLView : public BGLView { public: HaikuGLView(BRect frame, uint32 type); diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp index 209cb5cec4..c80365f1f3 100644 --- a/platform/haiku/os_haiku.cpp +++ b/platform/haiku/os_haiku.cpp @@ -28,9 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#include "drivers/gles3/rasterizer_gles3.h" + #include "os_haiku.h" -#include "drivers/gles3/rasterizer_gles3.h" #include "main/main.h" #include "servers/physics/physics_server_sw.h" #include "servers/visual/visual_server_raster.h" @@ -111,13 +112,12 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p context_gl->initialize(); context_gl->make_current(); context_gl->set_use_vsync(current_video_mode.use_vsync); - - /* Port to GLES 3 rasterizer */ - //rasterizer = memnew(RasterizerGLES2); + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); #endif - visual_server = memnew(VisualServerRaster(rasterizer)); + visual_server = memnew(VisualServerRaster()); ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE); @@ -138,8 +138,6 @@ Error OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p AudioDriverManager::initialize(p_audio_driver); - power_manager = memnew(PowerHaiku); - return OK; } @@ -152,7 +150,6 @@ void OS_Haiku::finalize() { visual_server->finish(); memdelete(visual_server); - memdelete(rasterizer); memdelete(input); @@ -336,7 +333,7 @@ String OS_Haiku::get_config_path() const { if (has_environment("XDG_CONFIG_HOME")) { return get_environment("XDG_CONFIG_HOME"); } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".config"); + return get_environment("HOME").plus_file("config/settings"); } else { return "."; } @@ -347,7 +344,7 @@ String OS_Haiku::get_data_path() const { if (has_environment("XDG_DATA_HOME")) { return get_environment("XDG_DATA_HOME"); } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".local/share"); + return get_environment("HOME").plus_file("config/data"); } else { return get_config_path(); } @@ -358,8 +355,23 @@ String OS_Haiku::get_cache_path() const { if (has_environment("XDG_CACHE_HOME")) { return get_environment("XDG_CACHE_HOME"); } else if (has_environment("HOME")) { - return get_environment("HOME").plus_file(".cache"); + return get_environment("HOME").plus_file("config/cache"); } else { return get_config_path(); } } + +OS::PowerState OS_Haiku::get_power_state() { + WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN"); + return OS::POWERSTATE_UNKNOWN; +} + +int OS_Haiku::get_power_seconds_left() { + WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); + return -1; +} + +int OS_Haiku::get_power_percent_left() { + WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); + return -1; +} diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h index 13d4420bde..e862eb44c3 100644 --- a/platform/haiku/os_haiku.h +++ b/platform/haiku/os_haiku.h @@ -37,9 +37,7 @@ #include "haiku_application.h" #include "haiku_direct_window.h" #include "main/input_default.h" -#include "power_haiku.h" #include "servers/audio_server.h" -#include "servers/visual/rasterizer.h" #include "servers/visual_server.h" class OS_Haiku : public OS_Unix { @@ -48,11 +46,9 @@ private: HaikuDirectWindow *window; MainLoop *main_loop; InputDefault *input; - Rasterizer *rasterizer; VisualServer *visual_server; VideoMode current_video_mode; int video_driver_index; - PowerHaiku *power_manager; #ifdef MEDIA_KIT_ENABLED AudioDriverMediaKit driver_media_kit; diff --git a/platform/haiku/platform_config.h b/platform/haiku/platform_config.h index bbd72dfeb6..72c8ee2535 100644 --- a/platform/haiku/platform_config.h +++ b/platform/haiku/platform_config.h @@ -34,3 +34,4 @@ #define _BSD_SOURCE 1 #define GLES3_INCLUDE_H "glad/glad.h" +#define GLES2_INCLUDE_H "glad/glad.h" diff --git a/platform/haiku/power_haiku.cpp b/platform/haiku/power_haiku.cpp deleted file mode 100644 index 2a26dd0f9c..0000000000 --- a/platform/haiku/power_haiku.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************/ -/* power_haiku.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "core/error_macros.h" - -#include "power_haiku.h" - -bool PowerHaiku::UpdatePowerInfo() { - - return false; -} - -OS::PowerState PowerHaiku::get_power_state() { - if (UpdatePowerInfo()) { - return power_state; - } else { - WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN"); - return OS::POWERSTATE_UNKNOWN; - } -} - -int PowerX11::get_power_seconds_left() { - if (UpdatePowerInfo()) { - return nsecs_left; - } else { - WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); - return -1; - } -} - -int PowerX11::get_power_percent_left() { - if (UpdatePowerInfo()) { - return percent_left; - } else { - WARN_PRINT("Power management is not implemented on this platform, defaulting to -1"); - return -1; - } -} - -PowerHaiku::PowerHaiku() : - nsecs_left(-1), - percent_left(-1), - power_state(OS::POWERSTATE_UNKNOWN) { -} - -PowerHaiku::~PowerHaiku() { -} diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index bd76db8796..d6cfd039d9 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -2309,6 +2309,8 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, if (r_exitcode) *r_exitcode = ret; + CloseHandle(pi.pi.hProcess); + CloseHandle(pi.pi.hThread); } else { ProcessID pid = pi.pi.dwProcessId; @@ -2322,17 +2324,15 @@ Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, Error OS_Windows::kill(const ProcessID &p_pid) { - HANDLE h; + ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED); - if (process_map->has(p_pid)) { - h = (*process_map)[p_pid].pi.hProcess; - process_map->erase(p_pid); - } else { + const PROCESS_INFORMATION pi = (*process_map)[p_pid].pi; + process_map->erase(p_pid); - ERR_FAIL_COND_V(!process_map->has(p_pid), FAILED); - }; + const int ret = TerminateProcess(pi.hProcess, 0); - int ret = TerminateProcess(h, 0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); return ret != 0 ? OK : FAILED; }; @@ -2789,23 +2789,17 @@ bool OS_Windows::is_disable_crash_handler() const { } Error OS_Windows::move_to_trash(const String &p_path) { - SHFILEOPSTRUCTA sf; - TCHAR *from = new TCHAR[p_path.length() + 2]; - strcpy(from, p_path.utf8().get_data()); - from[p_path.length()] = 0; - from[p_path.length() + 1] = 0; - + SHFILEOPSTRUCTW sf; sf.hwnd = hWnd; sf.wFunc = FO_DELETE; - sf.pFrom = from; + sf.pFrom = p_path.c_str(); sf.pTo = NULL; sf.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION; sf.fAnyOperationsAborted = FALSE; sf.hNameMappings = NULL; sf.lpszProgressTitle = NULL; - int ret = SHFileOperation(&sf); - delete[] from; + int ret = SHFileOperationW(&sf); if (ret) { ERR_PRINTS("SHFileOperation error: " + itos(ret)); diff --git a/platform_methods.py b/platform_methods.py index 0e0d93d0a6..4300216427 100644 --- a/platform_methods.py +++ b/platform_methods.py @@ -7,6 +7,11 @@ import subprocess # NOTE: The multiprocessing module is not compatible with SCons due to conflict on cPickle +if sys.version_info[0] < 3: + JSON_SERIALIZABLE_TYPES = (bool, int, long, float, basestring) +else: + JSON_SERIALIZABLE_TYPES = (bool, int, float, str) + def run_in_subprocess(builder_function): @@ -17,9 +22,9 @@ def run_in_subprocess(builder_function): target = [node.srcnode().abspath for node in target] source = [node.srcnode().abspath for node in source] - # Short circuit on non-Windows platforms - if os.name != 'nt': - return builder_function(target, source, None) + # Short circuit on non-Windows platforms, no need to run in subprocess + if sys.platform not in ('win32', 'cygwin'): + return builder_function(target, source, env) # Identify module module_name = builder_function.__module__ @@ -32,14 +37,25 @@ def run_in_subprocess(builder_function): subprocess_env = os.environ.copy() subprocess_env['PYTHONPATH'] = os.pathsep.join([os.getcwd()] + sys.path) + # Keep only JSON serializable environment items + filtered_env = dict( + (key, value) + for key, value in env.items() + if isinstance(value, JSON_SERIALIZABLE_TYPES) + ) + # Save parameters - args = (target, source, None) + args = (target, source, filtered_env) data = dict(fn=function_name, args=args) json_path = os.path.join(os.environ['TMP'], uuid.uuid4().hex + '.json') with open(json_path, 'wt') as json_file: json.dump(data, json_file, indent=2) + json_file_size = os.stat(json_path).st_size + + print('Executing builder function in subprocess: ' + 'module_path=%r, parameter_file=%r, parameter_file_size=%r, target=%r, source=%r' % ( + module_path, json_path, json_file_size, target, source)) try: - print('Executing builder function in subprocess: module_path=%r; data=%r' % (module_path, data)) exit_code = subprocess.call([sys.executable, module_path, json_path], env=subprocess_env) finally: try: diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index b3ff21457d..8758ffef9f 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -197,9 +197,9 @@ void StaticBody2D::set_friction(real_t p_friction) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_friction(p_friction); - _reload_physics_characteristics(); } real_t StaticBody2D::get_friction() const { @@ -223,9 +223,9 @@ void StaticBody2D::set_bounce(real_t p_bounce) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_bounce(p_bounce); - _reload_physics_characteristics(); } real_t StaticBody2D::get_bounce() const { @@ -243,7 +243,8 @@ real_t StaticBody2D::get_bounce() const { void StaticBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { - physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); } physics_material_override = p_physics_material_override; @@ -300,13 +301,9 @@ void StaticBody2D::_reload_physics_characteristics() { if (physics_material_override.is_null()) { Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0); Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT); } else { - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode()); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode()); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); } } @@ -625,9 +622,9 @@ void RigidBody2D::set_friction(real_t p_friction) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_friction(p_friction); - _reload_physics_characteristics(); } real_t RigidBody2D::get_friction() const { @@ -650,9 +647,9 @@ void RigidBody2D::set_bounce(real_t p_bounce) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_bounce(p_bounce); - _reload_physics_characteristics(); } real_t RigidBody2D::get_bounce() const { @@ -669,7 +666,8 @@ real_t RigidBody2D::get_bounce() const { void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { - physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); } physics_material_override = p_physics_material_override; @@ -1116,13 +1114,9 @@ void RigidBody2D::_reload_physics_characteristics() { if (physics_material_override.is_null()) { Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, 0); Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, 1); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, Physics2DServer::COMBINE_MODE_INHERIT); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, Physics2DServer::COMBINE_MODE_INHERIT); } else { - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); - Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, (Physics2DServer::CombineMode)physics_material_override->get_bounce_combine_mode()); - Physics2DServer::get_singleton()->body_set_combine_mode(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, (Physics2DServer::CombineMode)physics_material_override->get_friction_combine_mode()); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + Physics2DServer::get_singleton()->body_set_param(get_rid(), Physics2DServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); } } @@ -1210,6 +1204,9 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_ return colliding; } +//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45. +#define FLOOR_ANGLE_THRESHOLD 0.01 + Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) { Vector2 floor_motion = floor_velocity; @@ -1263,7 +1260,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const //all is a wall on_wall = true; } else { - if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor + if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor on_floor = true; on_floor_body = collision.collider_rid; @@ -1278,7 +1275,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const set_global_transform(gt); return Vector2(); } - } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling + } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling on_ceiling = true; } else { on_wall = true; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 78637cc097..80565fa455 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -368,7 +368,7 @@ void TileMap::update_dirty_quadrants() { } Rect2 r = tile_set->tile_get_region(c.id); - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { int spacing = tile_set->autotile_get_spacing(c.id); r.size = tile_set->autotile_get_size(c.id); r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y); @@ -491,7 +491,7 @@ void TileMap::update_dirty_quadrants() { if (navigation) { Ref<NavigationPolygon> navpoly; Vector2 npoly_ofs; - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); npoly_ofs = Vector2(); } else { @@ -563,7 +563,7 @@ void TileMap::update_dirty_quadrants() { } Ref<OccluderPolygon2D> occluder; - if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) { + if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y)); } else { occluder = tile_set->tile_get_light_occluder(c.id); @@ -631,11 +631,7 @@ void TileMap::_recompute_rect_cache() { r_total = r_total.merge(r); } - if (r_total == Rect2()) { - rect_cache = Rect2(-10, -10, 20, 20); - } else { - rect_cache = r_total.grow(MAX(cell_size.x, cell_size.y) * _get_quadrant_size()); - } + rect_cache = r_total; item_rect_changed(); @@ -840,7 +836,7 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { Map<PosKey, Cell>::Element *E = tile_map.find(p); if (E != NULL) { int id = get_cell(p_x, p_y); - if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) { + if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(id) == TileSet::ATLAS_TILE) { uint16_t mask = 0; if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) { if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { @@ -1152,6 +1148,11 @@ PoolVector<int> TileMap::_get_tile_data() const { return data; } +Rect2 TileMap::_edit_get_rect() const { + const_cast<TileMap *>(this)->update_dirty_quadrants(); + return rect_cache; +} + void TileMap::set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index c8aceac17d..52aa6e8e2a 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -223,6 +223,8 @@ public: INVALID_CELL = -1 }; + virtual Rect2 _edit_get_rect() const; + void set_tileset(const Ref<TileSet> &p_tileset); Ref<TileSet> get_tileset() const; diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 0fe427d5fc..2176b45faf 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -74,10 +74,7 @@ void Camera::_update_camera() { if (!is_inside_tree()) return; - Transform tr = get_camera_transform(); - tr.origin += tr.basis.get_axis(1) * v_offset; - tr.origin += tr.basis.get_axis(0) * h_offset; - VisualServer::get_singleton()->camera_set_transform(camera, tr); + VisualServer::get_singleton()->camera_set_transform(camera, get_camera_transform()); // here goes listener stuff /* @@ -143,7 +140,10 @@ void Camera::_notification(int p_what) { Transform Camera::get_camera_transform() const { - return get_global_transform().orthonormalized(); + Transform tr = get_global_transform().orthonormalized(); + tr.origin += tr.basis.get_axis(1) * v_offset; + tr.origin += tr.basis.get_axis(0) * h_offset; + return tr; } void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 4b3a4add4a..e53ccb4cf4 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -189,9 +189,10 @@ void StaticBody::set_friction(real_t p_friction) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } + physics_material_override->set_friction(p_friction); - _reload_physics_characteristics(); } real_t StaticBody::get_friction() const { @@ -215,9 +216,9 @@ void StaticBody::set_bounce(real_t p_bounce) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_bounce(p_bounce); - _reload_physics_characteristics(); } real_t StaticBody::get_bounce() const { @@ -235,7 +236,8 @@ real_t StaticBody::get_bounce() const { void StaticBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { - physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); } physics_material_override = p_physics_material_override; @@ -313,13 +315,9 @@ void StaticBody::_reload_physics_characteristics() { if (physics_material_override.is_null()) { PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0); PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT); } else { - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode()); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); } } @@ -626,9 +624,9 @@ void RigidBody::set_friction(real_t p_friction) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_friction(p_friction); - _reload_physics_characteristics(); } real_t RigidBody::get_friction() const { @@ -648,9 +646,9 @@ void RigidBody::set_bounce(real_t p_bounce) { if (physics_material_override.is_null()) { physics_material_override.instance(); + set_physics_material_override(physics_material_override); } physics_material_override->set_bounce(p_bounce); - _reload_physics_characteristics(); } real_t RigidBody::get_bounce() const { ERR_EXPLAIN("The method get_bounce has been deprecated and will be removed in the future, use physical material") @@ -665,7 +663,8 @@ real_t RigidBody::get_bounce() const { void RigidBody::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { if (physics_material_override.is_valid()) { - physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); + if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics")) + physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, this, "_reload_physics_characteristics"); } physics_material_override = p_physics_material_override; @@ -1070,13 +1069,9 @@ void RigidBody::_reload_physics_characteristics() { if (physics_material_override.is_null()) { PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, 0); PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, 1); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, PhysicsServer::COMBINE_MODE_INHERIT); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, PhysicsServer::COMBINE_MODE_INHERIT); } else { - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce()); - PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction()); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->get_bounce_combine_mode()); - PhysicsServer::get_singleton()->body_set_combine_mode(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->get_friction_combine_mode()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, physics_material_override->computed_bounce()); + PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, physics_material_override->computed_friction()); } } @@ -1130,6 +1125,9 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in return colliding; } +//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45. +#define FLOOR_ANGLE_THRESHOLD 0.01 + Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector3 lv = p_linear_velocity; @@ -1162,7 +1160,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve //all is a wall on_wall = true; } else { - if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor + if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //floor on_floor = true; floor_velocity = collision.collider_vel; @@ -1176,7 +1174,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve set_global_transform(gt); return floor_velocity - p_floor_direction * p_floor_direction.dot(floor_velocity); } - } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling + } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle + FLOOR_ANGLE_THRESHOLD)) { //ceiling on_ceiling = true; } else { on_wall = true; @@ -2044,6 +2042,8 @@ void PhysicalBone::_bind_methods() { ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics); + ClassDB::bind_method(D_METHOD("get_bone_id"), &PhysicalBone::get_bone_id); + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass); ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass); diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 4143989671..80bf422c98 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -557,6 +557,7 @@ protected: private: static Skeleton *find_skeleton_parent(Node *p_parent); + void _fix_joint_offset(); void _reload_joint(); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 4b6b59b2d3..c796e47f25 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -131,7 +131,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const { String prep = "bones/" + itos(i) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, prep + "name")); - p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(i - 1) + ",1")); + p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1")); p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest")); p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled")); p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); @@ -139,6 +139,59 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const { } } +void Skeleton::_update_process_order() { + + if (!process_order_dirty) + return; + + Bone *bonesptr = bones.ptrw(); + int len = bones.size(); + + process_order.resize(len); + int *order = process_order.ptrw(); + for (int i = 0; i < len; i++) { + + if (bonesptr[i].parent >= len) { + //validate this just in case + ERR_PRINTS("Bone " + itos(i) + " has invalid parent: " + itos(bonesptr[i].parent)); + bonesptr[i].parent = -1; + } + order[i] = i; + bonesptr[i].sort_index = i; + } + //now check process order + int pass_count = 0; + while (pass_count < len * len) { + //using bubblesort because of simplicity, it wont run every frame though. + //bublesort worst case is O(n^2), and this may be an infinite loop if cyclic + bool swapped = false; + for (int i = 0; i < len; i++) { + int parent_idx = bonesptr[order[i]].parent; + if (parent_idx < 0) + continue; //do nothing because it has no parent + //swap indices + int parent_order = bonesptr[parent_idx].sort_index; + if (parent_order > i) { + bonesptr[order[i]].sort_index = parent_order; + bonesptr[parent_idx].sort_index = i; + //swap order + SWAP(order[i], order[parent_order]); + swapped = true; + } + } + + if (!swapped) + break; + pass_count++; + } + + if (pass_count == len * len) { + ERR_PRINT("Skeleton parenthood graph is cyclic"); + } + + process_order_dirty = false; +} + void Skeleton::_notification(int p_what) { switch (p_what) { @@ -181,19 +234,23 @@ void Skeleton::_notification(int p_what) { vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens + _update_process_order(); + + const int *order = process_order.ptr(); + // pose changed, rebuild cache of inverses if (rest_global_inverse_dirty) { // calculate global rests and invert them for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + Bone &b = bonesptr[order[i]]; if (b.parent >= 0) b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest; else b.rest_global_inverse = b.rest; } for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + Bone &b = bonesptr[order[i]]; b.rest_global_inverse.affine_invert(); } @@ -205,7 +262,7 @@ void Skeleton::_notification(int p_what) { for (int i = 0; i < len; i++) { - Bone &b = bonesptr[i]; + Bone &b = bonesptr[order[i]]; if (b.disable_rest) { if (b.enabled) { @@ -319,12 +376,13 @@ void Skeleton::add_bone(const String &p_name) { for (int i = 0; i < bones.size(); i++) { - ERR_FAIL_COND(bones[i].name == "p_name"); + ERR_FAIL_COND(bones[i].name == p_name); } Bone b; b.name = p_name; bones.push_back(b); + process_order_dirty = true; rest_global_inverse_dirty = true; _make_dirty(); @@ -368,10 +426,11 @@ int Skeleton::get_bone_count() const { void Skeleton::set_bone_parent(int p_bone, int p_parent) { ERR_FAIL_INDEX(p_bone, bones.size()); - ERR_FAIL_COND(p_parent != -1 && (p_parent < 0 || p_parent >= p_bone)); + ERR_FAIL_COND(p_parent != -1 && (p_parent < 0)); bones.write[p_bone].parent = p_parent; rest_global_inverse_dirty = true; + process_order_dirty = true; _make_dirty(); } @@ -379,6 +438,8 @@ void Skeleton::unparent_bone_and_rest(int p_bone) { ERR_FAIL_INDEX(p_bone, bones.size()); + _update_process_order(); + int parent = bones[p_bone].parent; while (parent >= 0) { bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest; @@ -387,6 +448,7 @@ void Skeleton::unparent_bone_and_rest(int p_bone) { bones.write[p_bone].parent = -1; bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing + process_order_dirty = true; _make_dirty(); } @@ -489,6 +551,8 @@ void Skeleton::clear_bones() { bones.clear(); rest_global_inverse_dirty = true; + process_order_dirty = true; + _make_dirty(); } @@ -538,12 +602,21 @@ void Skeleton::_make_dirty() { dirty = true; } +int Skeleton::get_process_order(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, bones.size(), -1); + _update_process_order(); + return process_order[p_idx]; +} + void Skeleton::localize_rests() { - for (int i = bones.size() - 1; i >= 0; i--) { + _update_process_order(); - if (bones[i].parent >= 0) - set_bone_rest(i, bones[bones[i].parent].rest.affine_inverse() * bones[i].rest); + for (int i = bones.size() - 1; i >= 0; i--) { + int idx = process_order[i]; + if (bones[idx].parent >= 0) { + set_bone_rest(idx, bones[bones[idx].parent].rest.affine_inverse() * bones[idx].rest); + } } } @@ -600,9 +673,12 @@ PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) { void Skeleton::_rebuild_physical_bones_cache() { const int b_size = bones.size(); for (int i = 0; i < b_size; ++i) { - bones.write[i].cache_parent_physical_bone = _get_physical_bone_parent(i); - if (bones[i].physical_bone) - bones[i].physical_bone->_on_bone_parent_changed(); + PhysicalBone *parent_pb = _get_physical_bone_parent(i); + if (parent_pb != bones[i].physical_bone) { + bones.write[i].cache_parent_physical_bone = parent_pb; + if (bones[i].physical_bone) + bones[i].physical_bone->_on_bone_parent_changed(); + } } } @@ -740,6 +816,8 @@ void Skeleton::_bind_methods() { #endif // _3D_DISABLED + ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation); + BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); } @@ -747,6 +825,7 @@ Skeleton::Skeleton() { rest_global_inverse_dirty = true; dirty = false; + process_order_dirty = true; skeleton = VisualServer::get_singleton()->skeleton_create(); set_notify_transform(true); } diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 9672acb57a..e044e08437 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -39,6 +39,8 @@ */ #ifndef _3D_DISABLED +typedef int BoneId; + class PhysicalBone; #endif // _3D_DISABLED @@ -52,6 +54,7 @@ class Skeleton : public Spatial { bool enabled; int parent; + int sort_index; //used for re-sorting process order bool ignore_animation; @@ -90,13 +93,15 @@ class Skeleton : public Spatial { bool rest_global_inverse_dirty; Vector<Bone> bones; + Vector<int> process_order; + bool process_order_dirty; RID skeleton; void _make_dirty(); bool dirty; - //bind helpers + // bind helpers Array _get_bound_child_nodes_to_bone(int p_bone) const { Array bound; @@ -110,6 +115,8 @@ class Skeleton : public Spatial { return bound; } + void _update_process_order(); + protected: bool _get(const StringName &p_path, Variant &r_ret) const; bool _set(const StringName &p_path, const Variant &p_value); @@ -170,6 +177,7 @@ public: Transform get_bone_custom_pose(int p_bone) const; void localize_rests(); // used for loaders and tools + int get_process_order(int p_idx); #ifndef _3D_DISABLED // Physical bone API diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index 4ab7013707..980c348c9b 100644 --- a/scene/3d/soft_body.cpp +++ b/scene/3d/soft_body.cpp @@ -133,8 +133,8 @@ bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const { if ("pinned_points" == which) { Array arr_ret; - const int pinned_points_indices_size = pinned_points_indices.size(); - PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + const int pinned_points_indices_size = pinned_points.size(); + PoolVector<PinnedPoint>::Read r = pinned_points.read(); arr_ret.resize(pinned_points_indices_size); for (int i = 0; i < pinned_points_indices_size; ++i) { @@ -157,7 +157,7 @@ bool SoftBody::_get(const StringName &p_name, Variant &r_ret) const { void SoftBody::_get_property_list(List<PropertyInfo> *p_list) const { - const int pinned_points_indices_size = pinned_points_indices.size(); + const int pinned_points_indices_size = pinned_points.size(); p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "pinned_points")); @@ -173,17 +173,17 @@ bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) { const int p_indices_size = p_indices.size(); { // Remove the pined points on physics server that will be removed by resize - PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); - if (p_indices_size < pinned_points_indices.size()) { - for (int i = pinned_points_indices.size() - 1; i >= p_indices_size; --i) { + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + if (p_indices_size < pinned_points.size()) { + for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) { pin_point(r[i].point_index, false); } } } - pinned_points_indices.resize(p_indices_size); + pinned_points.resize(p_indices_size); - PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); + PoolVector<PinnedPoint>::Write w = pinned_points.write(); int point_index; for (int i = 0; i < p_indices_size; ++i) { point_index = p_indices.get(i); @@ -198,16 +198,16 @@ bool SoftBody::_set_property_pinned_points_indices(const Array &p_indices) { } bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) { - if (pinned_points_indices.size() <= p_item) { + if (pinned_points.size() <= p_item) { return false; } if ("spatial_attachment_path" == p_what) { - PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); + PoolVector<PinnedPoint>::Write w = pinned_points.write(); pin_point(w[p_item].point_index, true, p_value); _make_cache_dirty(); } else if ("offset" == p_what) { - PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); + PoolVector<PinnedPoint>::Write w = pinned_points.write(); w[p_item].offset = p_value; } else { return false; @@ -217,10 +217,10 @@ bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String & } bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const { - if (pinned_points_indices.size() <= p_item) { + if (pinned_points.size() <= p_item) { return false; } - PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + PoolVector<PinnedPoint>::Read r = pinned_points.read(); if ("point_index" == p_what) { r_ret = r[p_item].point_index; @@ -236,6 +236,8 @@ bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Var } void SoftBody::_changed_callback(Object *p_changed, const char *p_prop) { + update_physics_server(); + _reset_points_offsets(); #ifdef TOOLS_ENABLED if (p_changed == this) { update_configuration_warning(); @@ -247,8 +249,10 @@ void SoftBody::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_WORLD: { - if (Engine::get_singleton()->is_editor_hint()) + if (Engine::get_singleton()->is_editor_hint()) { + add_change_receptor(this); + } RID space = get_world()->get_space(); PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space); @@ -261,8 +265,10 @@ void SoftBody::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - if (Engine::get_singleton()->is_editor_hint()) + if (Engine::get_singleton()->is_editor_hint()) { + _reset_points_offsets(); return; + } PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); @@ -280,8 +286,8 @@ void SoftBody::_notification(int p_what) { _update_cache_pin_points_datas(); // Submit bone attachment - const int pinned_points_indices_size = pinned_points_indices.size(); - PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); + const int pinned_points_indices_size = pinned_points.size(); + PoolVector<PinnedPoint>::Read r = pinned_points.read(); for (int i = 0; i < pinned_points_indices_size; ++i) { if (r[i].spatial_attachment) { PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); @@ -531,15 +537,15 @@ const NodePath &SoftBody::get_parent_collision_ignore() const { } void SoftBody::set_pinned_points_indices(PoolVector<SoftBody::PinnedPoint> p_pinned_points_indices) { - pinned_points_indices = p_pinned_points_indices; - PoolVector<PinnedPoint>::Read w = pinned_points_indices.read(); - for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + pinned_points = p_pinned_points_indices; + PoolVector<PinnedPoint>::Read w = pinned_points.read(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { pin_point(p_pinned_points_indices[i].point_index, true); } } PoolVector<SoftBody::PinnedPoint> SoftBody::get_pinned_points_indices() { - return pinned_points_indices; + return pinned_points; } void SoftBody::add_collision_exception_with(Node *p_node) { @@ -685,8 +691,8 @@ SoftBody::~SoftBody() { void SoftBody::reset_softbody_pin() { PhysicsServer::get_singleton()->soft_body_remove_all_pinned_points(physics_rid); - PoolVector<PinnedPoint>::Read pps = pinned_points_indices.read(); - for (int i = pinned_points_indices.size() - 1; 0 < i; --i) { + PoolVector<PinnedPoint>::Read pps = pinned_points.read(); + for (int i = pinned_points.size() - 1; 0 < i; --i) { PhysicsServer::get_singleton()->soft_body_pin_point(physics_rid, pps[i].point_index, true); } } @@ -701,8 +707,8 @@ void SoftBody::_update_cache_pin_points_datas() { pinned_points_cache_dirty = false; - PoolVector<PinnedPoint>::Write w = pinned_points_indices.write(); - for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { if (!w[i].spatial_attachment_path.is_empty()) { w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(w[i].spatial_attachment_path)); @@ -731,7 +737,7 @@ void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_at pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index)); } - pinned_points_indices.push_back(pp); + pinned_points.push_back(pp); } else { @@ -745,10 +751,29 @@ void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_at } } +void SoftBody::_reset_points_offsets() { + + if (!Engine::get_singleton()->is_editor_hint()) + return; + + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + PoolVector<PinnedPoint>::Write w = pinned_points.write(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { + + if (!r[i].spatial_attachment) + w[i].spatial_attachment = Object::cast_to<Spatial>(get_node(r[i].spatial_attachment_path)); + + if (!r[i].spatial_attachment) + continue; + + w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index)); + } +} + void SoftBody::_remove_pinned_point(int p_point_index) { const int id(_has_pinned_point(p_point_index)); if (-1 != id) { - pinned_points_indices.remove(id); + pinned_points.remove(id); } } @@ -758,14 +783,14 @@ int SoftBody::_get_pinned_point(int p_point_index, SoftBody::PinnedPoint *&r_poi r_point = NULL; return -1; } else { - r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points_indices.read()[id]); + r_point = const_cast<SoftBody::PinnedPoint *>(&pinned_points.read()[id]); return id; } } int SoftBody::_has_pinned_point(int p_point_index) const { - PoolVector<PinnedPoint>::Read r = pinned_points_indices.read(); - for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + PoolVector<PinnedPoint>::Read r = pinned_points.read(); + for (int i = pinned_points.size() - 1; 0 <= i; --i) { if (p_point_index == r[i].point_index) { return i; } diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h index 6cf19ef8c4..cee32b9651 100644 --- a/scene/3d/soft_body.h +++ b/scene/3d/soft_body.h @@ -87,7 +87,7 @@ private: uint32_t collision_mask; uint32_t collision_layer; NodePath parent_collision_ignore; - PoolVector<PinnedPoint> pinned_points_indices; + PoolVector<PinnedPoint> pinned_points; bool simulation_started; bool pinned_points_cache_dirty; @@ -184,10 +184,14 @@ public: private: void reset_softbody_pin(); + void _make_cache_dirty(); void _update_cache_pin_points_datas(); + void _pin_point_on_physics_server(int p_point_index, bool pin); void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path); + void _reset_points_offsets(); + void _remove_pinned_point(int p_point_index); int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const; int _has_pinned_point(int p_point_index) const; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 64cb9ec4ca..3f494264e7 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -202,6 +202,7 @@ void Spatial::_notification(int p_what) { #ifdef TOOLS_ENABLED if (data.gizmo.is_valid()) { data.gizmo->free(); + data.gizmo.unref(); } #endif @@ -793,13 +794,13 @@ void Spatial::_bind_methods() { //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ; ADD_GROUP("Transform", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); - + ADD_GROUP("Matrix", ""); + ADD_PROPERTYNZ(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); ADD_GROUP("Visibility", ""); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo"); diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 653714dc98..bc054a8763 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -51,6 +51,7 @@ public: virtual bool can_draw() const = 0; SpatialGizmo(); + virtual ~SpatialGizmo() {} }; class Spatial : public Node { diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 2782354432..a660665d3f 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1644,7 +1644,7 @@ void AnimationPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position"); ADD_GROUP("Playback Options", "playback_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_animation_process_mode", "get_animation_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); @@ -1656,6 +1656,7 @@ void AnimationPlayer::_bind_methods() { BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); + BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); } AnimationPlayer::AnimationPlayer() { diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 49c73e54ad..f50b2454ec 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -65,6 +65,7 @@ public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, + ANIMATION_PROCESS_MANUAL, }; private: diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index de9f82dadc..8bbc05eed3 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -1199,6 +1199,11 @@ void AnimationTree::_process_graph(float p_delta) { } } +void AnimationTree::advance(float p_time) { + + _process_graph(p_time); +} + void AnimationTree::_notification(int p_what) { if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { @@ -1310,17 +1315,20 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_root_motion_transform"), &AnimationTree::get_root_motion_transform); + ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationTree::advance); + ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_tree_root", "get_tree_root"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode"); ADD_GROUP("Root Motion", "root_motion_"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track"); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE); + BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); } AnimationTree::AnimationTree() { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 540c36437a..87092a4a0e 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -133,6 +133,7 @@ public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, + ANIMATION_PROCESS_MANUAL, }; private: @@ -271,6 +272,8 @@ public: Transform get_root_motion_transform() const; + void advance(float p_time); + uint64_t get_last_process_pass() const; AnimationTree(); ~AnimationTree(); diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp new file mode 100644 index 0000000000..4991cedfab --- /dev/null +++ b/scene/animation/skeleton_ik.cpp @@ -0,0 +1,551 @@ +/*************************************************************************/ +/* skeleton_ik.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +/** + * @author AndreaCatania + */ + +#include "skeleton_ik.h" + +FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::find_child(const BoneId p_bone_id) { + for (int i = childs.size() - 1; 0 <= i; --i) { + if (p_bone_id == childs[i].bone) { + return &childs.write[i]; + } + } + return NULL; +} + +FabrikInverseKinematic::ChainItem *FabrikInverseKinematic::ChainItem::add_child(const BoneId p_bone_id) { + const int infant_child_id = childs.size(); + childs.resize(infant_child_id + 1); + childs.write[infant_child_id].bone = p_bone_id; + childs.write[infant_child_id].parent_item = this; + return &childs.write[infant_child_id]; +} + +/// Build a chain that starts from the root to tip +void FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain) { + + ERR_FAIL_COND(-1 == p_task->root_bone); + + Chain &chain(p_task->chain); + + chain.tips.resize(p_task->end_effectors.size()); + chain.chain_root.bone = p_task->root_bone; + chain.chain_root.initial_transform = p_task->skeleton->get_bone_global_pose(chain.chain_root.bone); + chain.chain_root.current_pos = chain.chain_root.initial_transform.origin; + chain.chain_root.pb = p_task->skeleton->get_physical_bone(chain.chain_root.bone); + chain.middle_chain_item = NULL; + + // Holds all IDs that are composing a single chain in reverse order + Vector<BoneId> chain_ids; + // This is used to know the chain size + int sub_chain_size; + // Resize only one time in order to fit all joints for performance reason + chain_ids.resize(p_task->skeleton->get_bone_count()); + + for (int x = p_task->end_effectors.size() - 1; 0 <= x; --x) { + + const EndEffector *ee(&p_task->end_effectors[x]); + ERR_FAIL_COND(p_task->root_bone >= ee->tip_bone); + ERR_FAIL_INDEX(ee->tip_bone, p_task->skeleton->get_bone_count()); + + sub_chain_size = 0; + // Picks all IDs that composing a single chain in reverse order (except the root) + BoneId chain_sub_tip(ee->tip_bone); + while (chain_sub_tip > p_task->root_bone) { + + chain_ids.write[sub_chain_size++] = chain_sub_tip; + chain_sub_tip = p_task->skeleton->get_bone_parent(chain_sub_tip); + } + + BoneId middle_chain_item_id = (((float)sub_chain_size) * 0.5); + + // Build chain by reading chain ids in reverse order + // For each chain item id will be created a ChainItem if doesn't exists + ChainItem *sub_chain(&chain.chain_root); + for (int i = sub_chain_size - 1; 0 <= i; --i) { + + ChainItem *child_ci(sub_chain->find_child(chain_ids[i])); + if (!child_ci) { + + child_ci = sub_chain->add_child(chain_ids[i]); + + child_ci->pb = p_task->skeleton->get_physical_bone(child_ci->bone); + + child_ci->initial_transform = p_task->skeleton->get_bone_global_pose(child_ci->bone); + child_ci->current_pos = child_ci->initial_transform.origin; + + if (child_ci->parent_item) { + child_ci->length = (child_ci->current_pos - child_ci->parent_item->current_pos).length(); + } + } + + sub_chain = child_ci; + + if (middle_chain_item_id == i) { + chain.middle_chain_item = child_ci; + } + } + + if (!middle_chain_item_id) + chain.middle_chain_item = NULL; + + // Initialize current tip + chain.tips.write[x].chain_item = sub_chain; + chain.tips.write[x].end_effector = ee; + + if (p_force_simple_chain) { + // NOTE: + // This is an "hack" that force to create only one tip per chain since the solver of multi tip (end effector) + // is not yet created. + // Remove this code when this is done + break; + } + } +} + +void FabrikInverseKinematic::update_chain(const Skeleton *p_sk, ChainItem *p_chain_item) { + + if (!p_chain_item) + return; + + p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone); + p_chain_item->current_pos = p_chain_item->initial_transform.origin; + + for (int i = p_chain_item->childs.size() - 1; 0 <= i; --i) { + update_chain(p_sk, &p_chain_item->childs.write[i]); + } +} + +void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) { + + real_t distance_to_goal(1e4); + real_t previous_distance_to_goal(0); + int can_solve(p_task->max_iterations); + while (distance_to_goal > p_task->min_distance && Math::abs(previous_distance_to_goal - distance_to_goal) > 0.005 && can_solve) { + previous_distance_to_goal = distance_to_goal; + --can_solve; + + solve_simple_backwards(p_task->chain, p_solve_magnet); + solve_simple_forwards(p_task->chain, p_solve_magnet); + + distance_to_goal = (p_task->chain.tips[0].chain_item->current_pos - p_task->chain.tips[0].end_effector->goal_transform.origin).length(); + } +} + +void FabrikInverseKinematic::solve_simple_backwards(Chain &r_chain, bool p_solve_magnet) { + + if (p_solve_magnet && !r_chain.middle_chain_item) { + return; + } + + Vector3 goal; + ChainItem *sub_chain_tip; + if (p_solve_magnet) { + goal = r_chain.magnet_position; + sub_chain_tip = r_chain.middle_chain_item; + } else { + goal = r_chain.tips[0].end_effector->goal_transform.origin; + sub_chain_tip = r_chain.tips[0].chain_item; + } + + while (sub_chain_tip) { + sub_chain_tip->current_pos = goal; + + if (sub_chain_tip->parent_item) { + // Not yet in the chain root + // So calculate next goal location + + const Vector3 look_parent((sub_chain_tip->parent_item->current_pos - sub_chain_tip->current_pos).normalized()); + goal = sub_chain_tip->current_pos + (look_parent * sub_chain_tip->length); + + // [TODO] Constraints goes here + } + + sub_chain_tip = sub_chain_tip->parent_item; + } +} + +void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_magnet) { + + if (p_solve_magnet && !r_chain.middle_chain_item) { + return; + } + + ChainItem *sub_chain_root(&r_chain.chain_root); + Vector3 origin(r_chain.chain_root.initial_transform.origin); + + while (sub_chain_root) { // Reach the tip + sub_chain_root->current_pos = origin; + + if (!sub_chain_root->childs.empty()) { + + ChainItem &child(sub_chain_root->childs.write[0]); + + // Is not tip + // So calculate next origin location + + // Look child + sub_chain_root->current_ori = (child.current_pos - sub_chain_root->current_pos).normalized(); + origin = sub_chain_root->current_pos + (sub_chain_root->current_ori * child.length); + + // [TODO] Constraints goes here + + if (p_solve_magnet && sub_chain_root == r_chain.middle_chain_item) { + // In case of magnet solving this is the tip + sub_chain_root = NULL; + } else { + sub_chain_root = &child; + } + } else { + + // Is tip + sub_chain_root = NULL; + } + } +} + +FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) { + + FabrikInverseKinematic::EndEffector ee; + ee.tip_bone = tip_bone; + + Task *task(memnew(Task)); + task->skeleton = p_sk; + task->root_bone = root_bone; + task->end_effectors.push_back(ee); + task->goal_global_transform = goal_transform; + + build_chain(task); + + return task; +} + +void FabrikInverseKinematic::free_task(Task *p_task) { + if (p_task) + memdelete(p_task); +} + +void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) { + p_task->goal_global_transform = p_goal; +} + +void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta) { + + if (blending_delta >= 0.99f) { + // Update the end_effector (local transform) without blending + p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform; + } else { + + // End effector in local transform + const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors.write[0].tip_bone)); + + // Update the end_effector (local transform) by blending with current pose + p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta); + } +} + +void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position) { + + if (blending_delta <= 0.01f) { + return; // Skip solving + } + + make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse().scaled(p_task->skeleton->get_global_transform().get_basis().get_scale()), blending_delta); + + update_chain(p_task->skeleton, &p_task->chain.chain_root); + + if (p_use_magnet && p_task->chain.middle_chain_item) { + p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.linear_interpolate(p_magnet_position, blending_delta); + solve_simple(p_task, true); + } + solve_simple(p_task, false); + + // Assign new bone position. + ChainItem *ci(&p_task->chain.chain_root); + while (ci) { + Transform new_bone_pose(ci->initial_transform); + new_bone_pose.origin = ci->current_pos; + + if (!ci->childs.empty()) { + + /// Rotate basis + const Vector3 initial_ori((ci->childs[0].initial_transform.origin - ci->initial_transform.origin).normalized()); + const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized()); + + if (rot_axis[0] != 0 && rot_axis[1] != 0 && rot_axis[2] != 0) { + const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1))); + new_bone_pose.basis.rotate(rot_axis, rot_angle); + } + } else { + // Set target orientation to tip + new_bone_pose.basis = p_task->chain.tips[0].end_effector->goal_transform.basis; + } + + p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); + + if (!ci->childs.empty()) + ci = &ci->childs.write[0]; + else + ci = NULL; + } +} + +void SkeletonIK::_validate_property(PropertyInfo &property) const { + + if (property.name == "root_bone" || property.name == "tip_bone") { + + if (skeleton) { + + String names; + for (int i = 0; i < skeleton->get_bone_count(); i++) { + if (i > 0) + names += ","; + names += skeleton->get_bone_name(i); + } + + property.hint = PROPERTY_HINT_ENUM; + property.hint_string = names; + } else { + + property.hint = PROPERTY_HINT_NONE; + property.hint_string = ""; + } + } +} + +void SkeletonIK::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_root_bone", "root_bone"), &SkeletonIK::set_root_bone); + ClassDB::bind_method(D_METHOD("get_root_bone"), &SkeletonIK::get_root_bone); + + ClassDB::bind_method(D_METHOD("set_tip_bone", "tip_bone"), &SkeletonIK::set_tip_bone); + ClassDB::bind_method(D_METHOD("get_tip_bone"), &SkeletonIK::get_tip_bone); + + ClassDB::bind_method(D_METHOD("set_interpolation", "interpolation"), &SkeletonIK::set_interpolation); + ClassDB::bind_method(D_METHOD("get_interpolation"), &SkeletonIK::get_interpolation); + + ClassDB::bind_method(D_METHOD("set_target_transform", "target"), &SkeletonIK::set_target_transform); + ClassDB::bind_method(D_METHOD("get_target_transform"), &SkeletonIK::get_target_transform); + + ClassDB::bind_method(D_METHOD("set_target_node", "node"), &SkeletonIK::set_target_node); + ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonIK::get_target_node); + + ClassDB::bind_method(D_METHOD("set_use_magnet", "use"), &SkeletonIK::set_use_magnet); + ClassDB::bind_method(D_METHOD("is_using_magnet"), &SkeletonIK::is_using_magnet); + + ClassDB::bind_method(D_METHOD("set_magnet_position", "local_position"), &SkeletonIK::set_magnet_position); + ClassDB::bind_method(D_METHOD("get_magnet_position"), &SkeletonIK::get_magnet_position); + + ClassDB::bind_method(D_METHOD("get_parent_skeleton"), &SkeletonIK::get_parent_skeleton); + ClassDB::bind_method(D_METHOD("is_running"), &SkeletonIK::is_running); + + ClassDB::bind_method(D_METHOD("set_min_distance", "min_distance"), &SkeletonIK::set_min_distance); + ClassDB::bind_method(D_METHOD("get_min_distance"), &SkeletonIK::get_min_distance); + + ClassDB::bind_method(D_METHOD("set_max_iterations", "iterations"), &SkeletonIK::set_max_iterations); + ClassDB::bind_method(D_METHOD("get_max_iterations"), &SkeletonIK::get_max_iterations); + + ClassDB::bind_method(D_METHOD("start", "one_time"), &SkeletonIK::start, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("stop"), &SkeletonIK::stop); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_bone"), "set_root_bone", "get_root_bone"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "tip_bone"), "set_tip_bone", "get_tip_bone"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node"), "set_target_node", "get_target_node"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_distance"), "set_min_distance", "get_min_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_iterations"), "set_max_iterations", "get_max_iterations"); +} + +void SkeletonIK::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + skeleton = Object::cast_to<Skeleton>(get_parent()); + reload_chain(); + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + + if (target_node_override) + reload_goal(); + + _solve_chain(); + + } break; + case NOTIFICATION_EXIT_TREE: { + reload_chain(); + } break; + } +} + +SkeletonIK::SkeletonIK() : + Node(), + interpolation(1), + skeleton(NULL), + target_node_override(NULL), + use_magnet(false), + min_distance(0.01), + max_iterations(10), + task(NULL) { + + set_process_priority(1); +} + +SkeletonIK::~SkeletonIK() { + FabrikInverseKinematic::free_task(task); + task = NULL; +} + +void SkeletonIK::set_root_bone(const StringName &p_root_bone) { + root_bone = p_root_bone; + reload_chain(); +} + +StringName SkeletonIK::get_root_bone() const { + return root_bone; +} + +void SkeletonIK::set_tip_bone(const StringName &p_tip_bone) { + tip_bone = p_tip_bone; + reload_chain(); +} + +StringName SkeletonIK::get_tip_bone() const { + return tip_bone; +} + +void SkeletonIK::set_interpolation(real_t p_interpolation) { + interpolation = p_interpolation; +} + +real_t SkeletonIK::get_interpolation() const { + return interpolation; +} + +void SkeletonIK::set_target_transform(const Transform &p_target) { + target = p_target; + reload_goal(); +} + +const Transform &SkeletonIK::get_target_transform() const { + return target; +} + +void SkeletonIK::set_target_node(const NodePath &p_node) { + target_node_path_override = p_node; + target_node_override = NULL; + reload_goal(); +} + +NodePath SkeletonIK::get_target_node() { + return target_node_path_override; +} + +void SkeletonIK::set_use_magnet(bool p_use) { + use_magnet = p_use; +} + +bool SkeletonIK::is_using_magnet() const { + return use_magnet; +} + +void SkeletonIK::set_magnet_position(const Vector3 &p_local_position) { + magnet_position = p_local_position; +} + +const Vector3 &SkeletonIK::get_magnet_position() const { + return magnet_position; +} + +void SkeletonIK::set_min_distance(real_t p_min_distance) { + min_distance = p_min_distance; +} + +void SkeletonIK::set_max_iterations(int p_iterations) { + max_iterations = p_iterations; +} + +bool SkeletonIK::is_running() { + return is_processing_internal(); +} + +void SkeletonIK::start(bool p_one_time) { + if (p_one_time) { + set_process_internal(false); + _solve_chain(); + } else { + set_process_internal(true); + } +} + +void SkeletonIK::stop() { + set_process_internal(false); +} + +Transform SkeletonIK::_get_target_transform() { + + if (!target_node_override && !target_node_path_override.is_empty()) + target_node_override = Object::cast_to<Spatial>(get_node(target_node_path_override)); + + if (target_node_override) + return target_node_override->get_global_transform(); + else + return target; +} + +void SkeletonIK::reload_chain() { + + FabrikInverseKinematic::free_task(task); + task = NULL; + + if (!skeleton) + return; + + task = FabrikInverseKinematic::create_simple_task(skeleton, skeleton->find_bone(root_bone), skeleton->find_bone(tip_bone), _get_target_transform()); + task->max_iterations = max_iterations; + task->min_distance = min_distance; +} + +void SkeletonIK::reload_goal() { + if (!task) + return; + + FabrikInverseKinematic::set_goal(task, _get_target_transform()); +} + +void SkeletonIK::_solve_chain() { + if (!task) + return; + FabrikInverseKinematic::solve(task, interpolation, use_magnet, magnet_position); +} diff --git a/scene/animation/skeleton_ik.h b/scene/animation/skeleton_ik.h new file mode 100644 index 0000000000..366c599c01 --- /dev/null +++ b/scene/animation/skeleton_ik.h @@ -0,0 +1,212 @@ +/*************************************************************************/ +/* skeleton_ik.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SKELETON_IK_H +#define SKELETON_IK_H + +/** + * @author AndreaCatania + */ + +#include "core/math/transform.h" +#include "scene/3d/skeleton.h" + +class FabrikInverseKinematic { + + struct EndEffector { + BoneId tip_bone; + Transform goal_transform; + }; + + struct ChainItem { + + Vector<ChainItem> childs; + ChainItem *parent_item; + + // Bone info + BoneId bone; + PhysicalBone *pb; + + real_t length; + /// Positions relative to root bone + Transform initial_transform; + Vector3 current_pos; + // Direction from this bone to child + Vector3 current_ori; + + ChainItem() : + parent_item(NULL), + bone(-1), + pb(NULL), + length(0) {} + + ChainItem *find_child(const BoneId p_bone_id); + ChainItem *add_child(const BoneId p_bone_id); + }; + + struct ChainTip { + ChainItem *chain_item; + const EndEffector *end_effector; + + ChainTip() : + chain_item(NULL), + end_effector(NULL) {} + + ChainTip(ChainItem *p_chain_item, const EndEffector *p_end_effector) : + chain_item(p_chain_item), + end_effector(p_end_effector) {} + + ChainTip(const ChainTip &p_other_ct) : + chain_item(p_other_ct.chain_item), + end_effector(p_other_ct.end_effector) {} + }; + + struct Chain { + ChainItem chain_root; + ChainItem *middle_chain_item; + Vector<ChainTip> tips; + Vector3 magnet_position; + }; + +public: + struct Task : public RID_Data { + RID self; + Skeleton *skeleton; + + Chain chain; + + // Settings + real_t min_distance; + int max_iterations; + + // Bone data + BoneId root_bone; + Vector<EndEffector> end_effectors; + + Transform goal_global_transform; + + Task() : + skeleton(NULL), + min_distance(0.01), + max_iterations(10), + root_bone(-1) {} + }; + +private: + /// Init a chain that starts from the root to tip + static void build_chain(Task *p_task, bool p_force_simple_chain = true); + + static void update_chain(const Skeleton *p_sk, ChainItem *p_chain_item); + + static void solve_simple(Task *p_task, bool p_solve_magnet); + /// Special solvers that solve only chains with one end effector + static void solve_simple_backwards(Chain &r_chain, bool p_solve_magnet); + static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet); + +public: + static Task *create_simple_task(Skeleton *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform); + static void free_task(Task *p_task); + // The goal of chain should be always in local space + static void set_goal(Task *p_task, const Transform &p_goal); + static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta); + static void solve(Task *p_task, real_t blending_delta, bool p_use_magnet, const Vector3 &p_magnet_position); +}; + +class SkeletonIK : public Node { + GDCLASS(SkeletonIK, Node); + + StringName root_bone; + StringName tip_bone; + real_t interpolation; + Transform target; + NodePath target_node_path_override; + bool use_magnet; + Vector3 magnet_position; + + real_t min_distance; + int max_iterations; + + Skeleton *skeleton; + Spatial *target_node_override; + FabrikInverseKinematic::Task *task; + +protected: + virtual void + _validate_property(PropertyInfo &property) const; + + static void _bind_methods(); + virtual void _notification(int p_notification); + +public: + SkeletonIK(); + virtual ~SkeletonIK(); + + void set_root_bone(const StringName &p_root_bone); + StringName get_root_bone() const; + + void set_tip_bone(const StringName &p_tip_bone); + StringName get_tip_bone() const; + + void set_interpolation(real_t p_interpolation); + real_t get_interpolation() const; + + void set_target_transform(const Transform &p_target); + const Transform &get_target_transform() const; + + void set_target_node(const NodePath &p_node); + NodePath get_target_node(); + + void set_use_magnet(bool p_use); + bool is_using_magnet() const; + + void set_magnet_position(const Vector3 &p_constraint); + const Vector3 &get_magnet_position() const; + + void set_min_distance(real_t p_min_distance); + real_t get_min_distance() const { return min_distance; } + + void set_max_iterations(int p_iterations); + int get_max_iterations() const { return max_iterations; } + + Skeleton *get_parent_skeleton() const { return skeleton; } + + bool is_running(); + + void start(bool p_one_time = false); + void stop(); + +private: + Transform _get_target_transform(); + void reload_chain(); + void reload_goal(); + void _solve_chain(); +}; + +#endif // SKELETON_IK_H diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 81fdc32788..ac8751f2bb 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -615,7 +615,7 @@ void Tween::_tween_process(float p_delta) { emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false)); // not repeat mode, remove completed action if (!repeat) - call_deferred("_remove", object, NodePath(Vector<StringName>(), data.key, false), true); + call_deferred("_remove", object, data.concatenated_key, true); } else if (!repeat) all_finished = all_finished && data.finish; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 4d73ee2d56..549daecdae 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -66,6 +66,12 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { + if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { + clear_button_status.press_attempt = true; + clear_button_status.pressing_inside = true; + return; + } + shift_selection_check_pre(b->get_shift()); set_cursor_at_pixel_pos(b->get_position().x); @@ -102,6 +108,15 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } else { + if (!text.empty() && is_editable() && clear_button_enabled) { + bool press_attempt = clear_button_status.press_attempt; + clear_button_status.press_attempt = false; + if (press_attempt && clear_button_status.pressing_inside && _is_over_clear_button(b->get_position())) { + clear(); + return; + } + } + if ((!selection.creating) && (!selection.doubleclick)) { deselect(); } @@ -119,6 +134,14 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (m.is_valid()) { + if (!text.empty() && is_editable() && clear_button_enabled) { + bool last_press_inside = clear_button_status.pressing_inside; + clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position()); + if (last_press_inside != clear_button_status.pressing_inside) { + update(); + } + } + if (m->get_button_mask() & BUTTON_LEFT) { if (selection.creating) { @@ -550,6 +573,25 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { } } +Control::CursorShape LineEdit::get_cursor_shape(const Point2 &p_pos) const { + if (!text.empty() && is_editable() && _is_over_clear_button(p_pos)) { + return CURSOR_ARROW; + } + return Control::get_cursor_shape(p_pos); +} + +bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { + if (!clear_button_enabled || !has_point(p_pos)) { + return false; + } + Ref<Texture> icon = Control::get_icon("clear"); + int x_ofs = get_stylebox("normal")->get_offset().x; + if (p_pos.x > get_size().width - icon->get_width() - x_ofs) { + return true; + } + return false; +} + void LineEdit::_notification(int p_what) { switch (p_what) { @@ -642,7 +684,7 @@ void LineEdit::_notification(int p_what) { int char_ofs = window_pos; int y_area = height - style->get_minimum_size().height; - int y_ofs = style->get_offset().y; + int y_ofs = style->get_offset().y + (y_area - font->get_height()) / 2; int font_ascent = font->get_ascent(); @@ -657,10 +699,26 @@ void LineEdit::_notification(int p_what) { font_color.a *= placeholder_alpha; font_color.a *= disabled_alpha; - if (has_icon("right_icon")) { - Ref<Texture> r_icon = Control::get_icon("right_icon"); - ofs_max -= r_icon->get_width(); - r_icon->draw(ci, Point2(width - r_icon->get_width() - x_ofs, height / 2 - r_icon->get_height() / 2), Color(1, 1, 1, disabled_alpha * .9)); + bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; + if (right_icon.is_valid() || display_clear_icon) { + Ref<Texture> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon; + Color color_icon(1, 1, 1, disabled_alpha * .9); + if (display_clear_icon) { + if (clear_button_status.press_attempt && clear_button_status.pressing_inside) { + color_icon = get_color("clear_button_color_pressed"); + } else { + color_icon = get_color("clear_button_color"); + } + } + r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); + + if (align == ALIGN_CENTER) { + if (window_pos == 0) { + x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); + } + } else { + x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); + } } int caret_height = font->get_height() > y_area ? y_area : font->get_height(); @@ -1096,9 +1154,8 @@ void LineEdit::set_cursor_position(int p_pos) { } else if (cursor_pos > window_pos) { /* Adjust window if cursor goes too much to the right */ int window_width = get_size().width - style->get_minimum_size().width; - if (has_icon("right_icon")) { - Ref<Texture> r_icon = Control::get_icon("right_icon"); - window_width -= r_icon->get_width(); + if (right_icon.is_valid()) { + window_width -= right_icon->get_width(); } if (window_width < 0) @@ -1385,10 +1442,26 @@ void LineEdit::set_expand_to_text_length(bool p_enabled) { } bool LineEdit::get_expand_to_text_length() const { - return expand_to_text_length; } +void LineEdit::set_clear_button_enabled(bool p_enabled) { + clear_button_enabled = p_enabled; + update(); +} + +bool LineEdit::is_clear_button_enabled() const { + return clear_button_enabled; +} + +void LineEdit::set_right_icon(const Ref<Texture> &p_icon) { + if (right_icon == p_icon) { + return; + } + right_icon = p_icon; + update(); +} + void LineEdit::_ime_text_callback(void *p_self, String p_text, Point2 p_selection) { LineEdit *self = (LineEdit *)p_self; self->ime_text = p_text; @@ -1481,6 +1554,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled); ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled); + ClassDB::bind_method(D_METHOD("set_clear_button_enabled", "enable"), &LineEdit::set_clear_button_enabled); + ClassDB::bind_method(D_METHOD("is_clear_button_enabled"), &LineEdit::is_clear_button_enabled); ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text"))); ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text"))); @@ -1508,6 +1583,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length"); ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled"); ADD_GROUP("Placeholder", "placeholder_"); ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder"); ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha"); @@ -1532,6 +1608,7 @@ LineEdit::LineEdit() { secret_character = "*"; text_changed_dirty = false; placeholder_alpha = 0.6; + clear_button_enabled = false; deselect(); set_focus_mode(FOCUS_ALL); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index e9314ba8dd..5294d99da0 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -87,6 +87,10 @@ private: int cached_width; int cached_placeholder_width; + bool clear_button_enabled; + + Ref<Texture> right_icon; + struct Selection { int begin; @@ -105,6 +109,13 @@ private: List<TextOperation> undo_stack; List<TextOperation>::Element *undo_stack_pos; + struct ClearButtonStatus { + bool press_attempt; + bool pressing_inside; + } clear_button_status; + + bool _is_over_clear_button(const Point2 &p_pos) const; + void _clear_undo_stack(); void _clear_redo(); void _create_undo_state(); @@ -150,6 +161,8 @@ public: virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const; virtual void drop_data(const Point2 &p_point, const Variant &p_data); + virtual CursorShape get_cursor_shape(const Point2 &p_pos) const; + void menu_option(int p_option); void set_context_menu_enabled(bool p_enable); bool is_context_menu_enabled(); @@ -201,6 +214,11 @@ public: void set_expand_to_text_length(bool p_enabled); bool get_expand_to_text_length() const; + void set_clear_button_enabled(bool p_enabled); + bool is_clear_button_enabled() const; + + void set_right_icon(const Ref<Texture> &p_icon); + virtual bool is_text_field() const; LineEdit(); ~LineEdit(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index ab762e19ee..cdc6b868ec 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -1049,10 +1049,8 @@ void PopupMenu::activate_item(int p_item) { ERR_FAIL_INDEX(p_item, items.size()); ERR_FAIL_COND(items[p_item].separator); int id = items[p_item].ID >= 0 ? items[p_item].ID : p_item; - emit_signal("id_pressed", id); - emit_signal("index_pressed", p_item); - //hide all parent PopupMenue's + //hide all parent PopupMenus Node *next = get_parent(); PopupMenu *pop = Object::cast_to<PopupMenu>(next); while (pop) { @@ -1086,6 +1084,9 @@ void PopupMenu::activate_item(int p_item) { return; hide(); + + emit_signal("id_pressed", id); + emit_signal("index_pressed", p_item); } void PopupMenu::remove_item(int p_idx) { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c9dcf058aa..9a8dc62e4e 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1177,7 +1177,12 @@ void TextEdit::_notification(int p_what) { int yofs = ofs_y + (get_row_height() - cache.font->get_height()) / 2; int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, yofs + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color); if (underlined) { - draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, 1), in_selection && override_selected_font_color ? cache.font_selected_color : color); + float line_width = 1.0; +#ifdef TOOLS_ENABLED + line_width *= EDSCALE; +#endif + + draw_rect(Rect2(char_ofs + char_margin + ofs_x, yofs + ascent + 2, w, line_width), in_selection && override_selected_font_color ? cache.font_selected_color : color); } } else if (draw_tabs && str[j] == '\t') { int yofs = (get_row_height() - cache.tab_icon->get_height()) / 2; @@ -2195,9 +2200,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { k->set_shift(false); } - if (!k->get_command()) { - _reset_caret_blink_timer(); - } + _reset_caret_blink_timer(); // save here for insert mode, just in case it is cleared in the following section bool had_selection = selection.active; @@ -5765,8 +5768,11 @@ void TextEdit::_update_completion_candidates() { } // Calculate the similarity to keep completions in good order float similarity; - if (completion_strings[i].to_lower().begins_with(s.to_lower())) { - // Substrings are the best candidates + if (completion_strings[i].begins_with(s)) { + // Substrings (same case) are the best candidates + similarity = 1.2; + } else if (completion_strings[i].to_lower().begins_with(s.to_lower())) { + // then any substrings similarity = 1.1; } else { // Otherwise compute the similarity @@ -6410,7 +6416,7 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int } // check for dot or underscore or 'x' for hex notation in floating point number - if ((str[j] == '.' || str[j] == 'x' || str[j] == '_') && !in_word && prev_is_number && !is_number) { + if ((str[j] == '.' || str[j] == 'x' || str[j] == '_' || str[j] == 'f') && !in_word && prev_is_number && !is_number) { is_number = true; is_symbol = false; is_char = false; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 68de7b3a0a..372ad7367e 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1415,11 +1415,6 @@ bool Node::is_greater_than(const Node *p_node) const { return res; } -bool Node::has_priority_higher_than(const Node *p_node) const { - ERR_FAIL_NULL_V(p_node, false); - return data.process_priority > p_node->data.process_priority; -} - void Node::get_owned_by(Node *p_by, List<Node *> *p_owned) { if (data.owner == p_by) @@ -2560,6 +2555,9 @@ void Node::clear_internal_tree_resource_paths() { String Node::get_configuration_warning() const { + if (get_script_instance()) { + return get_script_instance()->call("_get_configuration_warning"); + } return String(); } @@ -2768,6 +2766,7 @@ void Node::_bind_methods() { BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_configuration_warning")); //ClassDB::bind_method(D_METHOD("get_child",&Node::get_child,PH("index"))); //ClassDB::bind_method(D_METHOD("get_node",&Node::get_node,PH("path"))); diff --git a/scene/main/node.h b/scene/main/node.h index 9ee0340678..f3422618ce 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -72,7 +72,7 @@ public: struct ComparatorWithPriority { - bool operator()(const Node *p_a, const Node *p_b) const { return p_b->has_priority_higher_than(p_a) || p_b->is_greater_than(p_a); } + bool operator()(const Node *p_a, const Node *p_b) const { return p_b->data.process_priority == p_a->data.process_priority ? p_b->is_greater_than(p_a) : p_b->data.process_priority > p_a->data.process_priority; } }; private: @@ -265,7 +265,6 @@ public: bool is_a_parent_of(const Node *p_node) const; bool is_greater_than(const Node *p_node) const; - bool has_priority_higher_than(const Node *p_node) const; NodePath get_path() const; NodePath get_path_to(const Node *p_node) const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index a4fd35304a..382bddfb4e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -204,6 +204,7 @@ #include "scene/3d/sprite_3d.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/visibility_notifier.h" +#include "scene/animation/skeleton_ik.h" #include "scene/resources/environment.h" #include "scene/resources/physics_material.h" #endif @@ -216,6 +217,7 @@ static ResourceFormatLoaderText *resource_loader_text = NULL; static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL; static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL; +static ResourceFormatLoaderTextureLayered *resource_loader_texture_layered = NULL; static ResourceFormatLoaderBMFont *resource_loader_bmfont = NULL; @@ -236,6 +238,9 @@ void register_scene_types() { resource_loader_stream_texture = memnew(ResourceFormatLoaderStreamTexture); ResourceLoader::add_resource_format_loader(resource_loader_stream_texture); + resource_loader_texture_layered = memnew(ResourceFormatLoaderTextureLayered); + ResourceLoader::add_resource_format_loader(resource_loader_texture_layered); + resource_loader_theme = memnew(ResourceFormatLoaderTheme); ResourceLoader::add_resource_format_loader(resource_loader_theme); @@ -361,6 +366,7 @@ void register_scene_types() { ClassDB::register_class<Spatial>(); ClassDB::register_virtual_class<SpatialGizmo>(); ClassDB::register_class<Skeleton>(); + ClassDB::register_class<SkeletonIK>(); ClassDB::register_class<AnimationPlayer>(); ClassDB::register_class<Tween>(); @@ -613,6 +619,9 @@ void register_scene_types() { ClassDB::register_class<ProxyTexture>(); ClassDB::register_class<AnimatedTexture>(); ClassDB::register_class<CubeMap>(); + ClassDB::register_virtual_class<TextureLayered>(); + ClassDB::register_class<Texture3D>(); + ClassDB::register_class<TextureArray>(); ClassDB::register_class<Animation>(); ClassDB::register_virtual_class<Font>(); ClassDB::register_class<BitmapFont>(); @@ -726,6 +735,7 @@ void unregister_scene_types() { memdelete(resource_loader_dynamic_font); memdelete(resource_loader_stream_texture); + memdelete(resource_loader_texture_layered); memdelete(resource_loader_theme); DynamicFont::finish_dynamic_fonts(); diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index 85e36abf4e..39206ed043 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "bit_mask.h" + #include "io/image_loader.h" void BitMap::create(const Size2 &p_size) { @@ -189,13 +190,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) { //square value /* - checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent - +---+---+ - | 1 | 2 | - +---+---+ - | 4 | 8 | <- current pixel (curx,cury) - +---+---+ - */ + checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent + +---+---+ + | 1 | 2 | + +---+---+ + | 4 | 8 | <- current pixel (curx,cury) + +---+---+ + */ //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2)); Point2i tl = Point2i(curx - 1, cury - 1); @@ -215,13 +216,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 5: case 13: /* going UP with these cases: - 1 5 13 - +---+---+ +---+---+ +---+---+ - | 1 | | | 1 | | | 1 | | - +---+---+ +---+---+ +---+---+ - | | | | 4 | | | 4 | 8 | - +---+---+ +---+---+ +---+---+ - */ + 1 5 13 + +---+---+ +---+---+ +---+---+ + | 1 | | | 1 | | | 1 | | + +---+---+ +---+---+ +---+---+ + | | | | 4 | | | 4 | 8 | + +---+---+ +---+---+ +---+---+ + */ stepx = 0; stepy = -1; break; @@ -230,13 +231,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 10: case 11: /* going DOWN with these cases: - 8 10 11 - +---+---+ +---+---+ +---+---+ - | | | | | 2 | | 1 | 2 | - +---+---+ +---+---+ +---+---+ - | | 8 | | | 8 | | | 8 | - +---+---+ +---+---+ +---+---+ - */ + 8 10 11 + +---+---+ +---+---+ +---+---+ + | | | | | 2 | | 1 | 2 | + +---+---+ +---+---+ +---+---+ + | | 8 | | | 8 | | | 8 | + +---+---+ +---+---+ +---+---+ + */ stepx = 0; stepy = 1; break; @@ -245,13 +246,13 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 12: case 14: /* going LEFT with these cases: - 4 12 14 - +---+---+ +---+---+ +---+---+ - | | | | | | | | 2 | - +---+---+ +---+---+ +---+---+ - | 4 | | | 4 | 8 | | 4 | 8 | - +---+---+ +---+---+ +---+---+ - */ + 4 12 14 + +---+---+ +---+---+ +---+---+ + | | | | | | | | 2 | + +---+---+ +---+---+ +---+---+ + | 4 | | | 4 | 8 | | 4 | 8 | + +---+---+ +---+---+ +---+---+ + */ stepx = -1; stepy = 0; break; @@ -260,25 +261,25 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) case 3: case 7: /* going RIGHT with these cases: - 2 3 7 - +---+---+ +---+---+ +---+---+ - | | 2 | | 1 | 2 | | 1 | 2 | - +---+---+ +---+---+ +---+---+ - | | | | | | | 4 | | - +---+---+ +---+---+ +---+---+ - */ + 2 3 7 + +---+---+ +---+---+ +---+---+ + | | 2 | | 1 | 2 | | 1 | 2 | + +---+---+ +---+---+ +---+---+ + | | | | | | | 4 | | + +---+---+ +---+---+ +---+---+ + */ stepx = 1; stepy = 0; break; case 9: /* - +---+---+ - | 1 | | - +---+---+ - | | 8 | - +---+---+ - this should normally go UP, but if we already been here, we go down - */ + +---+---+ + | 1 | | + +---+---+ + | | 8 | + +---+---+ + this should normally go UP, but if we already been here, we go down + */ if (case9s.has(Point2i(curx, cury))) { //found, so we go down, and delete from case9s; stepx = 0; @@ -293,14 +294,14 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) break; case 6: /* - 6 - +---+---+ - | | 2 | - +---+---+ - | 4 | | - +---+---+ - this normally go RIGHT, but if its coming from UP, it should go LEFT - */ + 6 + +---+---+ + | | 2 | + +---+---+ + | 4 | | + +---+---+ + this normally go RIGHT, but if its coming from UP, it should go LEFT + */ if (case6s.has(Point2i(curx, cury))) { //found, so we go down, and delete from case6s; stepx = -1; @@ -418,31 +419,91 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, return result; } +struct FillBitsStackEntry { + Point2i pos; + int i; + int j; +}; + static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) { - for (int i = p_pos.x - 1; i <= p_pos.x + 1; i++) { - for (int j = p_pos.y - 1; j <= p_pos.y + 1; j++) { + // Using a custom stack to work iteratively to avoid stack overflow on big bitmaps + PoolVector<FillBitsStackEntry> stack; + // Tracking size since we won't be shrinking the stack vector + int stack_size = 0; - if (i < rect.position.x || i >= rect.position.x + rect.size.x) - continue; - if (j < rect.position.y || j >= rect.position.y + rect.size.y) - continue; + Point2i pos = p_pos; + int next_i; + int next_j; - if (p_map->get_bit(Vector2(i, j))) - continue; + bool reenter = true; + bool popped = false; + do { + if (reenter) { + next_i = pos.x - 1; + next_j = pos.y - 1; + reenter = false; + } + + for (int i = next_i; i <= pos.x + 1; i++) { + for (int j = next_j; j <= pos.y + 1; j++) { + if (popped) { + // The next loop over j must start normally + next_j = pos.y; + popped = false; + // Skip because an iteration was already executed with current counter values + continue; + } - else if (p_src->get_bit(Vector2(i, j))) { - p_map->set_bit(Vector2(i, j), true); - fill_bits(p_src, p_map, Point2i(i, j), rect); + if (i < rect.position.x || i >= rect.position.x + rect.size.x) + continue; + if (j < rect.position.y || j >= rect.position.y + rect.size.y) + continue; + + if (p_map->get_bit(Vector2(i, j))) + continue; + + else if (p_src->get_bit(Vector2(i, j))) { + p_map->set_bit(Vector2(i, j), true); + + FillBitsStackEntry se = { pos, i, j }; + stack.resize(MAX(stack_size + 1, stack.size())); + stack.set(stack_size, se); + stack_size++; + + pos = Point2i(i, j); + reenter = true; + break; + } + } + if (reenter) { + break; } } - } + if (!reenter) { + if (stack_size) { + FillBitsStackEntry se = stack.get(stack_size - 1); + stack_size--; + pos = se.pos; + next_i = se.i; + next_j = se.j; + popped = true; + } + } + } while (reenter || popped); + +#ifdef DEBUG_ENABLED + print_line("max stack size: " + itos(stack.size())); +#endif } + Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const { Rect2i r = Rect2i(0, 0, width, height).clip(p_rect); +#ifdef DEBUG_ENABLED print_line("Rect: " + r); +#endif Point2i from; Ref<BitMap> fill; fill.instance(); @@ -454,9 +515,13 @@ Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, fl if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) { Vector<Vector2> polygon = _march_square(r, Point2i(j, i)); +#ifdef DEBUG_ENABLED print_line("pre reduce: " + itos(polygon.size())); +#endif polygon = reduce(polygon, r, p_epsilon); +#ifdef DEBUG_ENABLED print_line("post reduce: " + itos(polygon.size())); +#endif polygons.push_back(polygon); fill_bits(this, fill, Point2i(j, i), r); } @@ -510,6 +575,34 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { } } +Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const { + + Vector<Vector<Vector2> > result = clip_opaque_to_polygons(p_rect, p_epsilon); + + // Convert result to bindable types + + Array result_array; + result_array.resize(result.size()); + for (int i = 0; i < result.size(); i++) { + + const Vector<Vector2> &polygon = result[i]; + + PoolVector2Array polygon_array; + polygon_array.resize(polygon.size()); + + { + PoolVector2Array::Write w = polygon_array.write(); + for (int j = 0; j < polygon.size(); j++) { + w[j] = polygon[j]; + } + } + + result_array[i] = polygon_array; + } + + return result_array; +} + void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create); @@ -526,6 +619,9 @@ void BitMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data); ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data); + ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask); + ClassDB::bind_method(D_METHOD("opaque_to_polygons", "rect", "epsilon"), &BitMap::_opaque_to_polygons_bind, DEFVAL(2.0)); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h index dcd5edb4fb..40f0bfb04a 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_mask.h @@ -46,6 +46,8 @@ class BitMap : public Resource { Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const; + Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const; + protected: void _set_data(const Dictionary &p_d); Dictionary _get_data() const; diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 601f6fb558..2d05f5e19f 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -434,9 +434,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_color_selected", "LineEdit", Color(0, 0, 0)); theme->set_color("cursor_color", "LineEdit", control_font_color_hover); theme->set_color("selection_color", "LineEdit", font_color_selection); + theme->set_color("clear_button_color", "LineEdit", control_font_color); + theme->set_color("clear_button_color_pressed", "LineEdit", control_font_color_pressed); theme->set_constant("minimum_spaces", "LineEdit", 12 * scale); + theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png)); + // ProgressBar theme->set_stylebox("bg", "ProgressBar", make_stylebox(progress_bar_png, 4, 4, 4, 4, 0, 0, 0, 0)); diff --git a/scene/resources/default_theme/line_edit_clear.png b/scene/resources/default_theme/line_edit_clear.png Binary files differnew file mode 100644 index 0000000000..af2775a132 --- /dev/null +++ b/scene/resources/default_theme/line_edit_clear.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index c6b37cad5a..353e7eddbe 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -3,35 +3,35 @@ // png image block static const unsigned char arrow_down_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6d, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0x63, 0x60, 0x18, 0x74, 0x80, 0x11, 0xc6, 0x78, 0xf0, 0xe0, 0xc1, 0x7f, 0x7c, 0xa, 0x15, 0x14, 0x14, 0x18, 0x19, 0x18, 0x18, 0x18, 0x98, 0x48, 0xb5, 0x81, 0x7c, 0xd, 0x8c, 0x8c, 0x8c, 0xf1, 0xc, 0xc, 0xc, 0x5f, 0xb1, 0xa8, 0xf9, 0xce, 0xc8, 0xc8, 0x98, 0xe, 0x57, 0x87, 0x2c, 0x73, 0xff, 0xfe, 0x7d, 0xd, 0x6, 0x6, 0x86, 0x55, 0x8c, 0x8c, 0x8c, 0xba, 0x50, 0xa1, 0x1b, 0xcc, 0xcc, 0xcc, 0x61, 0xb2, 0xb2, 0xb2, 0x97, 0xb1, 0x6a, 0x60, 0x60, 0x60, 0x60, 0x78, 0xf1, 0xe2, 0x5, 0xf7, 0xcf, 0x9f, 0x3f, 0xa7, 0x30, 0x30, 0x30, 0x30, 0xb0, 0xb3, 0xb3, 0xe7, 0x48, 0x48, 0x48, 0x60, 0xb3, 0x75, 0x30, 0x1, 0x0, 0x28, 0x20, 0x14, 0xc2, 0x1b, 0xd0, 0x7c, 0xca, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x34, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x32, 0x78, 0xf0, 0x1f, 0x15, 0x52, 0x20, 0xf1, 0x30, 0xee, 0xc1, 0x17, 0xb8, 0xf0, 0xb7, 0x87, 0x69, 0x48, 0xb6, 0xdc, 0xd7, 0xb8, 0x7f, 0x9, 0x2c, 0x7c, 0xfd, 0xb1, 0x2e, 0x9a, 0x3, 0x5e, 0x70, 0x3f, 0x9c, 0xff, 0x70, 0xfe, 0xb, 0x6e, 0x6, 0xea, 0x3, 0x0, 0xfb, 0x81, 0x48, 0xb8, 0x4d, 0xe4, 0x75, 0xd9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char arrow_right_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6c, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0x63, 0x60, 0xa0, 0x35, 0x60, 0x44, 0xe6, 0x3c, 0x78, 0xf0, 0xe0, 0x3f, 0x8c, 0xfd, 0xff, 0xff, 0xff, 0x44, 0x45, 0x45, 0xc5, 0x5, 0xe8, 0x1a, 0x98, 0x70, 0x9a, 0xc4, 0xc8, 0x38, 0xe5, 0xe1, 0xc3, 0x87, 0xda, 0x44, 0x6b, 0x60, 0x60, 0x60, 0xe0, 0xfe, 0xff, 0xff, 0xff, 0xaa, 0x17, 0x2f, 0x5e, 0x70, 0x13, 0xab, 0x81, 0x81, 0x81, 0x81, 0x41, 0xeb, 0xe7, 0xcf, 0x9f, 0x53, 0x48, 0xd1, 0x80, 0x1, 0x8, 0x69, 0xb8, 0xc6, 0xce, 0xce, 0x9e, 0x43, 0xac, 0x86, 0xaf, 0x8c, 0x8c, 0x8c, 0x61, 0x12, 0x12, 0x12, 0x5f, 0x89, 0xd2, 0xf0, 0xff, 0xff, 0xff, 0x1c, 0x79, 0x79, 0xf9, 0xab, 0x84, 0x1d, 0x49, 0x6d, 0x0, 0x0, 0x8f, 0x30, 0x1e, 0x10, 0x6e, 0x79, 0xda, 0xf9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x17, 0x3c, 0xf8, 0xf, 0x82, 0xf7, 0x13, 0x70, 0x48, 0x3c, 0xf8, 0xf2, 0x50, 0x1b, 0x43, 0x2, 0xa, 0xaf, 0xbe, 0xe0, 0xc6, 0x2e, 0xf1, 0xff, 0xe1, 0x7c, 0x12, 0x24, 0x10, 0x46, 0x11, 0xb6, 0x1c, 0xe1, 0x5c, 0xa, 0x0, 0x0, 0xe0, 0x14, 0x48, 0xb1, 0x3d, 0x1b, 0x7a, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char background_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x44, 0xa4, 0x8a, 0xc6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x11, 0x50, 0x4c, 0x54, 0x45, 0x91, 0xc9, 0xab, 0x90, 0xc9, 0xab, 0x90, 0xc9, 0xaa, 0x90, 0xc8, 0xab, 0x91, 0xc9, 0xaa, 0x91, 0xc8, 0xab, 0x90, 0xc8, 0xaa, 0x8f, 0xc8, 0xab, 0x8f, 0xc9, 0xab, 0x8f, 0xc8, 0xaa, 0x90, 0xc7, 0xaa, 0x90, 0xc7, 0xab, 0x8f, 0xc7, 0xaa, 0x8f, 0xc7, 0xab, 0x8e, 0xc7, 0xab, 0x8e, 0xc6, 0xab, 0x8f, 0xc6, 0xab, 0x8e, 0xc6, 0xaa, 0x8f, 0xc6, 0xaa, 0x8e, 0xc7, 0xaa, 0x8e, 0xc5, 0xaa, 0x8e, 0xc5, 0xab, 0x8d, 0xc5, 0xaa, 0x8d, 0xc5, 0xab, 0x8d, 0xc6, 0xaa, 0x8d, 0xc6, 0xab, 0x8d, 0xc4, 0xaa, 0x8e, 0xc4, 0xab, 0x8d, 0xc4, 0xab, 0x8e, 0xc4, 0xaa, 0x8c, 0xc4, 0xaa, 0x8c, 0xc5, 0xaa, 0x8d, 0xc3, 0xab, 0x8d, 0xc3, 0xaa, 0x8c, 0xc3, 0xaa, 0x8c, 0xc4, 0xab, 0x8c, 0xc3, 0xab, 0x8c, 0xc2, 0xab, 0x8b, 0xc2, 0xaa, 0x8b, 0xc3, 0xaa, 0x8b, 0xc3, 0xab, 0x8c, 0xc2, 0xaa, 0x8b, 0xc2, 0xab, 0x8b, 0xc1, 0xaa, 0x8b, 0xc1, 0xab, 0x8a, 0xc2, 0xaa, 0x8a, 0xc1, 0xaa, 0x8a, 0xc0, 0xaa, 0x8b, 0xc0, 0xaa, 0x8a, 0xc1, 0xa9, 0x8a, 0xc0, 0xa9, 0x89, 0xc0, 0xaa, 0x8a, 0xbf, 0xaa, 0x89, 0xbf, 0xaa, 0x89, 0xbf, 0xa9, 0x8a, 0xbf, 0xa9, 0x88, 0xbf, 0xaa, 0x89, 0xbe, 0xaa, 0x89, 0xbe, 0xa9, 0x88, 0xbf, 0xa9, 0x88, 0xbe, 0xa9, 0x88, 0xbe, 0xaa, 0x88, 0xbd, 0xaa, 0x88, 0xbd, 0xa9, 0x89, 0xbd, 0xaa, 0x89, 0xbd, 0xa9, 0x87, 0xbe, 0xa9, 0x87, 0xbd, 0xaa, 0x87, 0xbe, 0xaa, 0x87, 0xbd, 0xa9, 0x87, 0xbc, 0xaa, 0x88, 0xbc, 0xa9, 0x88, 0xbc, 0xaa, 0x87, 0xbc, 0xa9, 0x86, 0xbc, 0xa9, 0x87, 0xbb, 0xaa, 0x87, 0xbb, 0xa9, 0x86, 0xbb, 0xa9, 0x86, 0xbc, 0xaa, 0x86, 0xbb, 0xaa, 0x86, 0xba, 0xaa, 0x86, 0xba, 0xa9, 0x85, 0xba, 0xa9, 0x85, 0xbb, 0xaa, 0x85, 0xbb, 0xa9, 0x85, 0xba, 0xaa, 0x85, 0xb9, 0xa9, 0x86, 0xb9, 0xa9, 0x86, 0xb9, 0xaa, 0x85, 0xb9, 0xaa, 0xff, 0xff, 0xff, 0x25, 0xe, 0xc5, 0xe1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x5a, 0x3, 0xbb, 0xa5, 0xa2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x2, 0xaa, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x45, 0x4b, 0xd, 0x63, 0x9a, 0x56, 0x14, 0xbd, 0x86, 0x2d, 0x24, 0x2b, 0xf8, 0x8a, 0x1, 0xcc, 0x18, 0x23, 0xcd, 0x8b, 0xc5, 0x2a, 0xa9, 0x6e, 0x51, 0x98, 0x58, 0x3e, 0xda, 0x52, 0x69, 0x9e, 0x4a, 0x10, 0xba, 0xb8, 0xec, 0xff, 0xff, 0x91, 0x9d, 0x47, 0xd2, 0xf5, 0xbc, 0xcb, 0x3d, 0x1f, 0xf7, 0x40, 0xd4, 0x23, 0x4c, 0x4f, 0x2, 0x9b, 0xa8, 0x93, 0x27, 0x9d, 0xa3, 0xe7, 0x50, 0xe9, 0xc9, 0x79, 0x69, 0x74, 0xf7, 0x9f, 0x7a, 0x8a, 0xd2, 0xfb, 0xf9, 0xf4, 0x25, 0x53, 0xd5, 0x33, 0xf4, 0xcf, 0xce, 0x90, 0x9d, 0xa8, 0xa, 0x80, 0x75, 0xaa, 0xc8, 0xca, 0xa9, 0xa2, 0x9c, 0xf4, 0x54, 0x52, 0x91, 0x9c, 0xab, 0x2a, 0x46, 0x42, 0xf9, 0xe5, 0xb4, 0x2b, 0xa9, 0xe7, 0xca, 0xab, 0x57, 0xc8, 0x15, 0x8d, 0x74, 0x4d, 0xd5, 0x25, 0x40, 0x8a, 0xae, 0xea, 0xda, 0xb9, 0xd6, 0x59, 0x55, 0x12, 0xfe, 0xd0, 0x49, 0xef, 0xb3, 0xbe, 0xfe, 0x5a, 0x37, 0x34, 0x66, 0x30, 0x5d, 0xd3, 0xfb, 0xfa, 0x80, 0x69, 0x3, 0x7d, 0x70, 0xd1, 0xd5, 0xfa, 0x9a, 0x4e, 0x3, 0xe3, 0x62, 0xd0, 0xd7, 0xd, 0xd6, 0x37, 0x98, 0xd1, 0xef, 0xf, 0xc0, 0x9a, 0xc1, 0x2e, 0xc, 0xc6, 0x2e, 0xd8, 0xeb, 0x1, 0x86, 0x98, 0x61, 0x32, 0x13, 0x7f, 0x33, 0x66, 0x49, 0x36, 0xba, 0x41, 0x68, 0x18, 0xdd, 0x66, 0x64, 0x5b, 0x96, 0x69, 0x59, 0x90, 0xd6, 0xf0, 0x72, 0x68, 0x9a, 0x43, 0xd3, 0xfa, 0xd5, 0x32, 0x2f, 0x6d, 0xe3, 0xd2, 0xb2, 0x98, 0x65, 0x30, 0x93, 0x1c, 0x7b, 0x88, 0x67, 0xdb, 0xa6, 0xd, 0x72, 0x7e, 0x1b, 0xba, 0xa8, 0xc0, 0xda, 0xbf, 0xf, 0x91, 0xba, 0xb6, 0x4b, 0x8e, 0xe7, 0x78, 0xee, 0xd0, 0x75, 0x87, 0x1e, 0xac, 0xe3, 0x60, 0x5f, 0x39, 0x57, 0xe, 0x84, 0xe7, 0xd8, 0xb6, 0x63, 0x5f, 0xd1, 0x1b, 0xe7, 0x9a, 0xcb, 0x92, 0xe7, 0xba, 0xae, 0xe7, 0xf0, 0x1b, 0xc7, 0xb9, 0x76, 0x3c, 0x8e, 0xb3, 0x87, 0x16, 0xbf, 0xf1, 0x88, 0x73, 0xee, 0x8c, 0x46, 0xd8, 0xd7, 0x7c, 0xe4, 0xf1, 0xef, 0x18, 0x79, 0x37, 0x9c, 0x7b, 0x6f, 0xbc, 0x11, 0x27, 0xfe, 0xd6, 0xf7, 0xf9, 0x98, 0xf3, 0x77, 0x13, 0xfe, 0x96, 0x8f, 0xb8, 0x3f, 0x96, 0x65, 0x9f, 0x4f, 0x38, 0x1f, 0x4f, 0xf8, 0x68, 0xc2, 0xc9, 0x7f, 0xc6, 0x74, 0xea, 0x73, 0x49, 0x13, 0xcc, 0x78, 0xe2, 0xfb, 0x13, 0x59, 0xf2, 0xdf, 0xf9, 0x63, 0xa, 0xa6, 0xfe, 0x34, 0xf0, 0xf1, 0xba, 0xe9, 0x20, 0x39, 0xf0, 0x6f, 0x83, 0xdb, 0x69, 0x10, 0x4c, 0x29, 0x78, 0x3f, 0xb, 0x50, 0x91, 0xe7, 0xc0, 0x9f, 0x61, 0xdd, 0x6, 0xb3, 0xd9, 0xcc, 0xf7, 0xdf, 0x83, 0xe0, 0x2, 0x9a, 0xcd, 0x67, 0xcf, 0x98, 0x77, 0xea, 0xf, 0x29, 0xe4, 0xfc, 0x9, 0x13, 0x40, 0xd0, 0x1c, 0x87, 0x1f, 0xb8, 0x93, 0xab, 0xb, 0xee, 0x5e, 0x62, 0x5a, 0x2c, 0xe7, 0x21, 0x78, 0xb9, 0x58, 0x2e, 0xb1, 0xd1, 0xb8, 0x5b, 0x84, 0x4b, 0xd8, 0xf9, 0x7c, 0x81, 0xef, 0x2e, 0xa4, 0xc5, 0x22, 0xc, 0x97, 0x61, 0x18, 0x85, 0x12, 0x51, 0x4, 0x5e, 0x46, 0x61, 0xf4, 0x97, 0x74, 0xb, 0xb9, 0xa8, 0x3b, 0xad, 0xe2, 0x38, 0xa, 0xd7, 0xab, 0x28, 0x4, 0x85, 0x1f, 0xe2, 0x10, 0x1c, 0xc5, 0xe1, 0x2a, 0x5c, 0x25, 0x2b, 0x4a, 0xe3, 0x38, 0x49, 0x93, 0x24, 0x4d, 0xe3, 0x34, 0x4e, 0xe2, 0x68, 0xd, 0x1f, 0xad, 0x93, 0x24, 0x59, 0x23, 0xfa, 0xb0, 0x4e, 0x53, 0xca, 0xf2, 0x2c, 0xfb, 0xf8, 0xf1, 0x13, 0x6c, 0x92, 0x42, 0xa7, 0x49, 0x9e, 0xe6, 0x69, 0x92, 0x49, 0xd3, 0x65, 0x94, 0x7d, 0xce, 0xb2, 0x2c, 0xc9, 0xd2, 0xa2, 0xf8, 0x92, 0xe7, 0x59, 0x51, 0xc0, 0x7d, 0xce, 0xb, 0xc8, 0x1c, 0xc8, 0x36, 0x5, 0x95, 0x5f, 0xb3, 0x72, 0x53, 0x66, 0xf7, 0x5f, 0x37, 0x70, 0xf7, 0x79, 0x51, 0x88, 0xfb, 0x12, 0x3d, 0x91, 0xdd, 0x8b, 0x4d, 0x99, 0x8b, 0x92, 0x44, 0x59, 0xa, 0x51, 0x8a, 0x72, 0xb, 0x2e, 0x37, 0x2, 0x1a, 0xa2, 0x0, 0x8b, 0xd, 0x62, 0x21, 0x48, 0xec, 0x76, 0x7b, 0x21, 0xaa, 0x52, 0xec, 0xb6, 0xa2, 0xaa, 0xb6, 0xf, 0xfb, 0x7d, 0x2d, 0xc4, 0xf6, 0xa1, 0x7a, 0x10, 0xdb, 0x9d, 0x28, 0x77, 0x15, 0x55, 0xbb, 0xba, 0x92, 0xd8, 0x57, 0xbb, 0xaa, 0xaa, 0xeb, 0x7d, 0x2d, 0xed, 0xff, 0xdf, 0xbe, 0xa6, 0x43, 0xd5, 0x34, 0x75, 0xd3, 0x54, 0xcd, 0xa1, 0xaa, 0xf, 0x75, 0x83, 0xbc, 0xae, 0x5a, 0xb4, 0x64, 0xf6, 0xd, 0x1d, 0x6a, 0x25, 0x9a, 0xa6, 0x6d, 0xab, 0x43, 0x3, 0xfc, 0x2d, 0x57, 0x8b, 0xf7, 0xf8, 0xd8, 0xb4, 0x87, 0xb6, 0x6e, 0xe9, 0xb1, 0x6d, 0x8e, 0x6d, 0x7b, 0x6c, 0xff, 0x39, 0x3e, 0x1d, 0x9f, 0x20, 0x8f, 0xd2, 0x1d, 0xff, 0x45, 0xa, 0xdd, 0xb6, 0x4f, 0xff, 0x1, 0xbe, 0xd3, 0xa6, 0xf7, 0x55, 0x9e, 0xe1, 0xf0, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x44, 0xa4, 0x8a, 0xc6, 0x0, 0x0, 0x1, 0xe, 0x50, 0x4c, 0x54, 0x45, 0x91, 0xc9, 0xab, 0x90, 0xc9, 0xab, 0x90, 0xc9, 0xaa, 0x90, 0xc8, 0xab, 0x91, 0xc9, 0xaa, 0x91, 0xc8, 0xab, 0x90, 0xc8, 0xaa, 0x8f, 0xc8, 0xab, 0x8f, 0xc9, 0xab, 0x8f, 0xc8, 0xaa, 0x90, 0xc7, 0xaa, 0x90, 0xc7, 0xab, 0x8f, 0xc7, 0xaa, 0x8f, 0xc7, 0xab, 0x8e, 0xc7, 0xab, 0x8e, 0xc6, 0xab, 0x8f, 0xc6, 0xab, 0x8e, 0xc6, 0xaa, 0x8f, 0xc6, 0xaa, 0x8e, 0xc7, 0xaa, 0x8e, 0xc5, 0xaa, 0x8e, 0xc5, 0xab, 0x8d, 0xc5, 0xaa, 0x8d, 0xc5, 0xab, 0x8d, 0xc6, 0xaa, 0x8d, 0xc6, 0xab, 0x8d, 0xc4, 0xaa, 0x8e, 0xc4, 0xab, 0x8d, 0xc4, 0xab, 0x8e, 0xc4, 0xaa, 0x8c, 0xc4, 0xaa, 0x8c, 0xc5, 0xaa, 0x8d, 0xc3, 0xab, 0x8d, 0xc3, 0xaa, 0x8c, 0xc3, 0xaa, 0x8c, 0xc4, 0xab, 0x8c, 0xc3, 0xab, 0x8c, 0xc2, 0xab, 0x8b, 0xc2, 0xaa, 0x8b, 0xc3, 0xaa, 0x8b, 0xc3, 0xab, 0x8c, 0xc2, 0xaa, 0x8b, 0xc2, 0xab, 0x8b, 0xc1, 0xaa, 0x8b, 0xc1, 0xab, 0x8a, 0xc2, 0xaa, 0x8a, 0xc1, 0xaa, 0x8a, 0xc0, 0xaa, 0x8b, 0xc0, 0xaa, 0x8a, 0xc1, 0xa9, 0x8a, 0xc0, 0xa9, 0x89, 0xc0, 0xaa, 0x8a, 0xbf, 0xaa, 0x89, 0xbf, 0xaa, 0x89, 0xbf, 0xa9, 0x8a, 0xbf, 0xa9, 0x88, 0xbf, 0xaa, 0x89, 0xbe, 0xaa, 0x89, 0xbe, 0xa9, 0x88, 0xbf, 0xa9, 0x88, 0xbe, 0xa9, 0x88, 0xbe, 0xaa, 0x88, 0xbd, 0xaa, 0x88, 0xbd, 0xa9, 0x89, 0xbd, 0xaa, 0x89, 0xbd, 0xa9, 0x87, 0xbe, 0xa9, 0x87, 0xbd, 0xaa, 0x87, 0xbe, 0xaa, 0x87, 0xbd, 0xa9, 0x87, 0xbc, 0xaa, 0x88, 0xbc, 0xa9, 0x88, 0xbc, 0xaa, 0x87, 0xbc, 0xa9, 0x86, 0xbc, 0xa9, 0x87, 0xbb, 0xaa, 0x87, 0xbb, 0xa9, 0x86, 0xbb, 0xa9, 0x86, 0xbc, 0xaa, 0x86, 0xbb, 0xaa, 0x86, 0xba, 0xaa, 0x86, 0xba, 0xa9, 0x85, 0xba, 0xa9, 0x85, 0xbb, 0xaa, 0x85, 0xbb, 0xa9, 0x85, 0xba, 0xaa, 0x85, 0xb9, 0xa9, 0x86, 0xb9, 0xa9, 0x86, 0xb9, 0xaa, 0x85, 0xb9, 0xaa, 0x3e, 0xa0, 0x4f, 0x4f, 0x0, 0x0, 0x2, 0x3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2d, 0x4a, 0x7, 0x82, 0x4, 0x37, 0x12, 0x2, 0xa, 0x4a, 0xea, 0x9e, 0xbd, 0xff, 0x3f, 0xf5, 0x6c, 0x4f, 0x4b, 0xda, 0x58, 0x91, 0x24, 0x10, 0x20, 0xf8, 0x5d, 0x20, 0x81, 0x1f, 0xa8, 0x1f, 0xf6, 0x7, 0xf5, 0x7d, 0x0, 0x0, 0x3c, 0x0, 0x8, 0x14, 0x28, 0xb8, 0x41, 0x0, 0x50, 0x7b, 0x70, 0x63, 0xc, 0x9, 0x1c, 0xaa, 0x52, 0xeb, 0x4, 0x5b, 0xfb, 0x1d, 0x89, 0x68, 0xe1, 0x39, 0x9c, 0x7d, 0x68, 0x77, 0x60, 0x8c, 0x7a, 0x80, 0xe5, 0x6e, 0xdc, 0x41, 0x47, 0x51, 0x5f, 0xb8, 0xdd, 0xed, 0xa0, 0x9f, 0xc6, 0xad, 0xba, 0xee, 0xfb, 0xee, 0xde, 0x97, 0x74, 0x6f, 0x98, 0x82, 0x26, 0x51, 0x30, 0xa6, 0x3f, 0x10, 0xc8, 0xad, 0x13, 0xe4, 0x83, 0x0, 0x7a, 0x4, 0x4a, 0xd9, 0x5c, 0xde, 0xd2, 0x16, 0x15, 0xf2, 0xac, 0xac, 0x3e, 0x8f, 0x5a, 0x15, 0x3a, 0x5a, 0xe0, 0x6a, 0x1, 0xdc, 0xbd, 0x9b, 0x47, 0x44, 0xb6, 0x1e, 0x44, 0x5b, 0xe7, 0x84, 0x4b, 0xc3, 0xc, 0x1b, 0x51, 0xeb, 0xaa, 0x54, 0xc7, 0xb3, 0xeb, 0xca, 0x1a, 0x36, 0xbc, 0x76, 0x64, 0x4a, 0x62, 0x54, 0x3c, 0xe7, 0xf4, 0xc0, 0xd4, 0x1b, 0xda, 0x48, 0xa4, 0xc1, 0xd7, 0x98, 0xc2, 0xac, 0x19, 0x76, 0xd7, 0x44, 0x80, 0x33, 0xfe, 0xcb, 0x2b, 0x97, 0x6d, 0x8e, 0x2, 0x36, 0x4a, 0xfd, 0xc, 0xef, 0xb1, 0x35, 0x76, 0x63, 0x62, 0xc6, 0x5b, 0x38, 0xd3, 0x7e, 0x0, 0x7b, 0xfe, 0xef, 0x48, 0x93, 0xff, 0xdc, 0x3d, 0xed, 0xf4, 0xc4, 0xc4, 0x99, 0x93, 0xd3, 0x68, 0x5c, 0x9e, 0xee, 0x87, 0x16, 0xca, 0x1f, 0xbb, 0x80, 0x9e, 0xa0, 0x5, 0x47, 0x0, 0xbc, 0x5f, 0x7, 0x79, 0xa9, 0x3, 0x99, 0x80, 0x8f, 0xa7, 0x16, 0x68, 0xcd, 0x3a, 0x3d, 0x32, 0x60, 0xc0, 0x6f, 0xd8, 0x2b, 0x8a, 0xe1, 0x20, 0xf, 0xe3, 0x4, 0xcf, 0xfa, 0x1a, 0xb, 0x90, 0xfb, 0x2a, 0x57, 0x4a, 0xa8, 0xc9, 0xb7, 0x91, 0x37, 0x82, 0xf7, 0x4c, 0xd2, 0xa9, 0x9a, 0x78, 0x8f, 0x53, 0x22, 0x40, 0xfd, 0x44, 0x5c, 0xdf, 0xeb, 0x89, 0x4a, 0xc9, 0x0, 0xe7, 0x74, 0x1, 0x28, 0xff, 0xa6, 0x7e, 0xa, 0x4, 0xe9, 0x43, 0xe2, 0x7, 0x7d, 0xaf, 0x9, 0xca, 0x61, 0x3, 0x88, 0x13, 0x20, 0xab, 0x50, 0x1e, 0x41, 0xbc, 0x68, 0x3, 0xd5, 0xc2, 0x69, 0xa4, 0x5b, 0x22, 0xbb, 0x35, 0xdc, 0x45, 0x72, 0x94, 0xba, 0x85, 0xee, 0x82, 0x54, 0x0, 0xcb, 0x45, 0xa4, 0x78, 0xa, 0xc0, 0x28, 0x1c, 0x91, 0x46, 0x50, 0xa3, 0x34, 0xcb, 0x63, 0xfa, 0xeb, 0xb8, 0xd8, 0x5e, 0x9e, 0xde, 0x2b, 0xa3, 0xda, 0x35, 0xd3, 0x62, 0xc4, 0x8e, 0xca, 0x39, 0xf0, 0xb1, 0x7a, 0xd6, 0x69, 0x5f, 0x5, 0xa1, 0xa4, 0xa3, 0x3a, 0xdf, 0x8, 0xd8, 0xcf, 0x62, 0xf7, 0x14, 0x4f, 0x5a, 0x87, 0xa5, 0xc1, 0x22, 0x51, 0xe2, 0xd5, 0x9a, 0xc1, 0x1c, 0x37, 0x5e, 0xd6, 0x7f, 0xed, 0xfb, 0x41, 0x5e, 0xb7, 0xf, 0x7c, 0xe3, 0xba, 0x7b, 0xd0, 0xa5, 0x3a, 0xb3, 0x8c, 0xd7, 0x2e, 0x4e, 0xd7, 0xba, 0xbb, 0xd7, 0xc6, 0xb, 0x8d, 0x17, 0x1f, 0xe3, 0x46, 0x9, 0x49, 0xa1, 0x8c, 0x13, 0x63, 0x4c, 0xa6, 0xfa, 0x2a, 0x8c, 0x38, 0x88, 0x6a, 0xc9, 0x32, 0x4c, 0x1b, 0xa3, 0x44, 0x43, 0xd9, 0x55, 0xdb, 0xce, 0xc1, 0xe9, 0x92, 0x2f, 0x4a, 0x25, 0x59, 0x36, 0x52, 0x52, 0x41, 0xc4, 0x16, 0x2, 0x41, 0x32, 0x7a, 0x73, 0x4b, 0x21, 0xb, 0x8, 0x57, 0x89, 0xc2, 0x90, 0x65, 0xa8, 0xdc, 0x46, 0x56, 0x14, 0x15, 0x8e, 0xc1, 0x20, 0xd7, 0xcc, 0x40, 0x76, 0x42, 0x3a, 0x83, 0xf, 0x83, 0x46, 0xf5, 0x27, 0xa7, 0x80, 0x7e, 0xcf, 0xd2, 0x74, 0xd0, 0x78, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char base_green_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x1, 0x3, 0x0, 0x0, 0x0, 0x49, 0xb4, 0xe8, 0xb7, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x90, 0xc9, 0xab, 0xff, 0xff, 0xff, 0xc6, 0xd0, 0x9d, 0x30, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x18, 0xdc, 0x0, 0x0, 0x0, 0xa0, 0x0, 0x1, 0x61, 0x25, 0x7d, 0x47, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x1, 0x3, 0x0, 0x0, 0x0, 0x49, 0xb4, 0xe8, 0xb7, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x90, 0xc9, 0xab, 0xff, 0xff, 0xff, 0xc6, 0xd0, 0x9d, 0x30, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0xe4, 0x0, 0x0, 0x0, 0xa0, 0x0, 0x1, 0xf3, 0xdb, 0xea, 0x79, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char button_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xd9, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x7d, 0x91, 0x41, 0x4e, 0xc3, 0x30, 0x14, 0x44, 0x9f, 0xed, 0x8f, 0x6d, 0x35, 0x8b, 0x9a, 0x6d, 0xb9, 0x6, 0xfb, 0xde, 0x81, 0xd3, 0xe4, 0x8, 0xf4, 0x32, 0xbd, 0x1, 0xb, 0x6e, 0xc0, 0x25, 0x60, 0x83, 0xa8, 0x2, 0x6a, 0xa4, 0xc6, 0x49, 0xfc, 0xbb, 0x88, 0x54, 0x11, 0x94, 0x30, 0xb3, 0xf9, 0xd2, 0x9f, 0x19, 0x8d, 0x34, 0x6, 0xc1, 0x13, 0x88, 0x78, 0x1c, 0x96, 0x9, 0x85, 0x91, 0xcc, 0x85, 0x8e, 0x2c, 0x78, 0x2a, 0x12, 0x5b, 0x2a, 0x2, 0x6, 0x3, 0x28, 0x4a, 0x47, 0xcb, 0x37, 0xd, 0x8, 0x81, 0xb4, 0x7f, 0x7a, 0xa8, 0x87, 0xc4, 0xc, 0xd2, 0xbc, 0x3f, 0xbf, 0x1e, 0x19, 0x84, 0xc8, 0x76, 0x57, 0x9f, 0xd2, 0x80, 0xfe, 0x7a, 0x1b, 0x24, 0xed, 0x6a, 0x5e, 0x38, 0xb, 0x9e, 0xaa, 0x4f, 0xfd, 0xdc, 0x8e, 0xd2, 0xd3, 0x27, 0x2a, 0xbc, 0xe0, 0x8, 0x65, 0xe6, 0xe6, 0xd6, 0x94, 0x80, 0x13, 0x2c, 0x46, 0x29, 0xb, 0x2, 0x5, 0x83, 0x15, 0xc0, 0xac, 0x26, 0x18, 0x90, 0xe9, 0x5c, 0x11, 0x30, 0x9, 0x54, 0x17, 0x5, 0xa, 0xa, 0x42, 0x41, 0xcb, 0x62, 0x87, 0x2, 0x4a, 0x11, 0x46, 0xba, 0xd5, 0x84, 0x8e, 0xd1, 0x92, 0x69, 0x6d, 0xe3, 0xd0, 0x3f, 0x74, 0xd8, 0x86, 0x96, 0xec, 0xb8, 0xc3, 0xa5, 0xaf, 0xfb, 0x47, 0x1f, 0x3d, 0xe1, 0xc6, 0x48, 0x3c, 0x7d, 0x1e, 0x3e, 0xde, 0xf8, 0x31, 0x6c, 0xfe, 0x1d, 0xab, 0x15, 0x32, 0x30, 0x70, 0x5e, 0x9b, 0xfb, 0xa, 0xbb, 0x7c, 0x61, 0xa2, 0x50, 0x44, 0x45, 0xca, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xc7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xd0, 0x81, 0x66, 0x43, 0x31, 0x14, 0x87, 0xf1, 0xf, 0x5, 0x17, 0xb8, 0x28, 0x2e, 0x8, 0x71, 0xf3, 0x6, 0x19, 0xb6, 0xb9, 0xcb, 0xac, 0x95, 0xa4, 0xb7, 0xad, 0x6a, 0xd5, 0x68, 0x5f, 0xe4, 0x3e, 0x76, 0x1e, 0xe1, 0xbf, 0x21, 0xa6, 0xab, 0xf8, 0x1, 0x7c, 0x9c, 0x73, 0xe, 0xac, 0xe8, 0xe8, 0x19, 0x30, 0x58, 0xc6, 0xca, 0x62, 0x18, 0xe8, 0xe9, 0x58, 0x41, 0xc7, 0x1a, 0x87, 0x27, 0x10, 0x49, 0xe4, 0x5f, 0x89, 0x48, 0xc0, 0xe3, 0x58, 0xd3, 0x41, 0x8f, 0xb, 0xcb, 0xbd, 0x7c, 0xeb, 0xbf, 0x7b, 0x9, 0xb, 0x8e, 0x1e, 0x6, 0xfc, 0xad, 0x64, 0x6d, 0xb5, 0x79, 0xb0, 0x55, 0xd6, 0xad, 0xe0, 0x19, 0xc0, 0x10, 0xae, 0xda, 0x34, 0x5c, 0x45, 0xc0, 0x80, 0x25, 0x5e, 0xf4, 0xd5, 0x70, 0x11, 0x11, 0xb, 0x23, 0xe9, 0xac, 0xcf, 0x86, 0xb3, 0x48, 0x8c, 0x30, 0x92, 0x4f, 0xa, 0xd, 0x27, 0x91, 0x6b, 0x70, 0xd4, 0x47, 0xc3, 0xf1, 0x2f, 0x48, 0x7, 0x4d, 0xd, 0x87, 0x3a, 0xc2, 0x12, 0x67, 0xbd, 0x37, 0xcc, 0x75, 0x49, 0x43, 0xd8, 0xe9, 0xad, 0x61, 0x57, 0xcf, 0x1c, 0xf0, 0xfb, 0x32, 0xe9, 0xf5, 0xc9, 0xa4, 0x7d, 0x7d, 0x54, 0x8f, 0x7b, 0x59, 0xe6, 0x92, 0x14, 0x1f, 0x24, 0xcd, 0x3f, 0x7b, 0x6b, 0xa, 0xe, 0x6a, 0x82, 0x91, 0x45, 0x30, 0xba, 0x1, 0x4a, 0x51, 0xc4, 0x35, 0x1f, 0xe5, 0xa1, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char button_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x4, 0x42, 0x26, 0xa1, 0xa1, 0xce, 0x8a, 0x40, 0x46, 0x7a, 0xe7, 0xcc, 0x99, 0x33, 0xca, 0x80, 0x8c, 0xd5, 0x20, 0xe1, 0x5d, 0x40, 0x1c, 0x3, 0x62, 0x1c, 0x5, 0xe2, 0x48, 0x10, 0x63, 0x2a, 0x7e, 0x6, 0x5c, 0x31, 0x58, 0xbb, 0x14, 0x10, 0xe7, 0xee, 0x9c, 0x39, 0x73, 0x1e, 0xc8, 0x40, 0x31, 0x98, 0x15, 0xe8, 0x0, 0x0, 0xec, 0xe0, 0x11, 0x6d, 0x2c, 0x6f, 0x45, 0x2b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x62, 0xed, 0x5e, 0xfc, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0x84, 0x4c, 0x42, 0x43, 0x9d, 0x15, 0x81, 0x8c, 0xf4, 0xce, 0x99, 0x33, 0x67, 0x94, 0x1, 0x19, 0xab, 0x41, 0xc2, 0xbb, 0x80, 0x38, 0x6, 0xc4, 0x38, 0xa, 0xc4, 0x91, 0x20, 0xc6, 0x54, 0x3c, 0xc, 0xb8, 0x62, 0x98, 0x76, 0x29, 0x20, 0xce, 0xdd, 0x39, 0x73, 0xe6, 0x3c, 0x90, 0x81, 0x62, 0x10, 0x2b, 0x30, 0x1, 0x0, 0xec, 0xe0, 0x11, 0x6d, 0xb5, 0xe0, 0x8c, 0x99, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char button_hover_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x5f, 0x5a, 0x6b, 0x56, 0x53, 0x64, 0x57, 0x53, 0x64, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x57, 0x53, 0x63, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5b, 0x57, 0x66, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x43, 0x40, 0x4c, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0xff, 0xff, 0xff, 0x99, 0x8b, 0x2e, 0x55, 0x0, 0x0, 0x0, 0x16, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0x6b, 0x28, 0x52, 0x7a, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x2e, 0x54, 0xd3, 0x10, 0x87, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x97, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x49, 0x12, 0x82, 0x30, 0x10, 0x5, 0xd0, 0xce, 0x48, 0x46, 0x40, 0x51, 0x4, 0x41, 0x45, 0xc4, 0x20, 0x88, 0xf7, 0xbf, 0x9e, 0x21, 0x45, 0x65, 0xa1, 0x6f, 0xd7, 0xbf, 0xaa, 0x27, 0x0, 0x84, 0x9, 0x65, 0xdc, 0x63, 0x94, 0x60, 0x4, 0x80, 0x12, 0x21, 0x95, 0x36, 0xd6, 0x1a, 0xad, 0xa4, 0x48, 0x10, 0x60, 0x91, 0x66, 0xe5, 0x29, 0x28, 0xb3, 0x54, 0x60, 0x20, 0x32, 0xaf, 0xea, 0x73, 0x50, 0x57, 0xb9, 0x24, 0x40, 0x55, 0xb3, 0xd5, 0x3e, 0x69, 0x14, 0x5, 0xa6, 0xdb, 0x4b, 0xd4, 0x6a, 0x6, 0xdc, 0x5c, 0x6f, 0xd1, 0xd5, 0x70, 0xe0, 0xb6, 0xbb, 0x47, 0x9d, 0x5d, 0x83, 0xfe, 0x11, 0xf5, 0x6b, 0x60, 0x86, 0x67, 0x34, 0xf8, 0x16, 0xa6, 0xdd, 0x18, 0x39, 0x3f, 0x94, 0x2a, 0x37, 0xbe, 0x36, 0xa3, 0xf3, 0x6b, 0x89, 0xdc, 0x4d, 0xf3, 0x3b, 0x98, 0xa7, 0xbd, 0x3f, 0xc, 0x8b, 0xe2, 0xb0, 0x7c, 0x82, 0xe5, 0x58, 0xf8, 0xd3, 0xff, 0x9e, 0xfb, 0x7d, 0xff, 0xb, 0x74, 0xeb, 0x15, 0x11, 0xe1, 0xa7, 0x60, 0xfc, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x5f, 0x5a, 0x6b, 0x56, 0x53, 0x64, 0x57, 0x53, 0x64, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x57, 0x53, 0x63, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5b, 0x57, 0x66, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x43, 0x40, 0x4c, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x40, 0xdc, 0xe6, 0x80, 0x0, 0x0, 0x0, 0x16, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0x6b, 0x28, 0x52, 0x7a, 0x0, 0x0, 0x0, 0x67, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xcf, 0x47, 0x2, 0x83, 0x30, 0x10, 0x43, 0x51, 0x69, 0x98, 0xf4, 0xe4, 0xfe, 0x87, 0x24, 0xfb, 0xf4, 0x8, 0xd1, 0xb1, 0x3f, 0xb8, 0xbd, 0xdd, 0x24, 0x38, 0x4, 0x40, 0x43, 0xc9, 0xfd, 0x24, 0x1a, 0x7a, 0x27, 0x2d, 0x7, 0xc2, 0x41, 0x2f, 0xbd, 0x69, 0x88, 0x23, 0x27, 0x38, 0x3d, 0xfd, 0x22, 0x2f, 0xd3, 0x1b, 0xc3, 0x35, 0xe9, 0x85, 0x39, 0xd, 0x10, 0x2c, 0x0, 0x25, 0x20, 0x81, 0x2d, 0xc0, 0xa0, 0x2d, 0x8, 0xa9, 0x12, 0x64, 0x0, 0x66, 0x91, 0xa5, 0x61, 0xf3, 0xbe, 0xc5, 0x18, 0xd9, 0x7e, 0x7e, 0x21, 0x45, 0x1b, 0x53, 0x77, 0x4a, 0xac, 0x87, 0x63, 0x3d, 0x7e, 0x7, 0x87, 0x7b, 0x3b, 0x5b, 0x7a, 0xd3, 0xea, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char button_normal_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0xff, 0xff, 0xff, 0xe5, 0x37, 0x10, 0x78, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x2d, 0xcd, 0xda, 0x41, 0x3d, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x93, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x47, 0x12, 0x82, 0x40, 0x10, 0x5, 0xd0, 0x9e, 0xc8, 0x44, 0x92, 0x22, 0x41, 0x54, 0x44, 0x40, 0x14, 0xef, 0x7f, 0x3e, 0x7, 0x8a, 0xea, 0x85, 0xbe, 0xe5, 0xaf, 0xea, 0xf0, 0x1, 0x8, 0x65, 0x5c, 0xc8, 0x40, 0x70, 0x46, 0x9, 0x0, 0x89, 0x94, 0x36, 0xd6, 0x79, 0xef, 0xac, 0xd1, 0x2a, 0x22, 0x40, 0x55, 0x9c, 0x14, 0xa7, 0x4d, 0x91, 0xc4, 0x8a, 0x2, 0xd3, 0x69, 0x59, 0xd5, 0x9b, 0xaa, 0x4c, 0x35, 0x3, 0x6e, 0x9a, 0xfa, 0xbc, 0xab, 0x1b, 0xc3, 0x41, 0xd8, 0xf6, 0x82, 0x5a, 0x2b, 0x40, 0xba, 0xeb, 0xd, 0x5d, 0x9d, 0x4, 0xe9, 0xbb, 0x3b, 0xea, 0xfc, 0x1a, 0xf4, 0xf, 0xd4, 0xaf, 0x81, 0x1b, 0x46, 0x34, 0x84, 0x11, 0x61, 0xa7, 0x27, 0x9a, 0xc2, 0x52, 0x6e, 0xe6, 0x17, 0x9a, 0xc3, 0x59, 0xa6, 0xb3, 0xf1, 0xbd, 0x1b, 0xb3, 0xf0, 0x18, 0x55, 0xf9, 0x61, 0xf9, 0x6c, 0x96, 0x63, 0x1e, 0x5e, 0xff, 0x2b, 0xf7, 0x5b, 0xff, 0xb, 0x69, 0x5a, 0x14, 0xfa, 0x84, 0xf6, 0xc2, 0x8, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x14, 0x4, 0xd1, 0x2e, 0x1c, 0xee, 0x7f, 0xca, 0xd1, 0xed, 0x28, 0x8d, 0x4b, 0x92, 0x5a, 0xbe, 0xe8, 0x2f, 0xc4, 0x9c, 0x24, 0xcf, 0x15, 0x54, 0xab, 0x78, 0xee, 0x53, 0x30, 0x4a, 0x85, 0xa6, 0xfc, 0xf1, 0x87, 0x11, 0xb2, 0x9a, 0x15, 0x9a, 0x37, 0x13, 0x74, 0xce, 0xb4, 0xd4, 0x77, 0xcb, 0xe, 0xb4, 0x96, 0x99, 0x10, 0x34, 0x81, 0x42, 0x50, 0x21, 0x9d, 0x41, 0x23, 0xf8, 0xc, 0x56, 0xe1, 0x10, 0x9c, 0x40, 0x4e, 0xfe, 0x6e, 0x72, 0x96, 0x7e, 0xd7, 0xdf, 0x3f, 0xb3, 0x79, 0x90, 0xcd, 0xf1, 0xc4, 0x26, 0x1e, 0x8e, 0x78, 0xfc, 0x1, 0xf5, 0x61, 0x3f, 0x44, 0xe8, 0xf1, 0xdd, 0xba, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char button_pressed_png[] = { @@ -39,19 +39,19 @@ static const unsigned char button_pressed_png[] = { }; static const unsigned char checked_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x12, 0x7b, 0xbc, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x8e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x5b, 0x12, 0x82, 0x30, 0xc, 0x40, 0x51, 0x48, 0x5b, 0x15, 0x5, 0x5b, 0x42, 0x2b, 0x4, 0x50, 0x40, 0xc5, 0xb7, 0xee, 0x7f, 0x79, 0x96, 0x8a, 0x88, 0x7a, 0x3f, 0xcf, 0x4c, 0x26, 0x89, 0xe7, 0xfd, 0xe5, 0x3, 0xe3, 0xc2, 0x35, 0x99, 0x82, 0x6f, 0x1, 0x66, 0x81, 0x54, 0xae, 0x18, 0xe7, 0x60, 0x81, 0x5, 0x89, 0x36, 0x5d, 0xab, 0x34, 0x5b, 0x30, 0xb, 0x5c, 0x6a, 0xa2, 0xbc, 0x20, 0x2a, 0x71, 0x2d, 0xb9, 0x5, 0xa1, 0xc, 0x6d, 0xb0, 0xa2, 0x1a, 0x9b, 0xad, 0x12, 0x3d, 0xec, 0x70, 0xdf, 0x36, 0x58, 0x9b, 0x1, 0xe, 0xc7, 0xd3, 0x19, 0x4b, 0xfa, 0x80, 0x9d, 0xc9, 0xd2, 0xcb, 0x18, 0xae, 0x88, 0x37, 0x1a, 0x43, 0x91, 0xdf, 0x1f, 0x6f, 0x70, 0x6b, 0x5f, 0x69, 0xb7, 0x76, 0x38, 0xcc, 0xe8, 0x24, 0xec, 0xe, 0x83, 0x28, 0xec, 0x4f, 0x97, 0xcb, 0x8, 0xbe, 0x9e, 0xe3, 0xcc, 0x3d, 0xf7, 0xd3, 0x13, 0x10, 0x58, 0xd, 0x44, 0xd4, 0xa5, 0x38, 0x3e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xca, 0x5, 0xb2, 0x2, 0x30, 0x18, 0x3, 0xe1, 0x4d, 0xed, 0xb9, 0x60, 0xf7, 0x3f, 0x20, 0xee, 0x4e, 0x99, 0xe0, 0xb0, 0x63, 0xfd, 0xbf, 0x86, 0xd7, 0x12, 0x72, 0x38, 0x69, 0x5b, 0x6b, 0x42, 0x45, 0xe5, 0xa, 0xab, 0x95, 0x41, 0x9f, 0x32, 0x20, 0x69, 0x2d, 0xbc, 0x50, 0x46, 0x3a, 0x10, 0x17, 0x5f, 0x49, 0x4, 0x7f, 0x90, 0x57, 0x89, 0xb7, 0xc5, 0x5f, 0x96, 0x17, 0x2e, 0x93, 0xcb, 0x8e, 0x3a, 0x83, 0xb, 0xc4, 0x8e, 0xd4, 0xff, 0x5c, 0x73, 0x83, 0x69, 0x9e, 0x95, 0xfc, 0x3b, 0xf4, 0x33, 0xe0, 0xf8, 0x61, 0xd3, 0xf1, 0x7d, 0x5d, 0x30, 0x7a, 0x6f, 0x89, 0xb, 0xd4, 0x5a, 0xe1, 0x40, 0xf, 0xfc, 0x34, 0x6c, 0xd2, 0x56, 0x80, 0xef, 0xfd, 0x9, 0xd2, 0x3a, 0x5e, 0x41, 0x15, 0x21, 0x77, 0x6, 0xc7, 0x6b, 0x47, 0x4e, 0x3a, 0x2f, 0x53, 0xb4, 0x10, 0xc7, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char checker_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1a, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc4, 0x0, 0x5, 0x98, 0xc, 0xc6, 0x7a, 0xc2, 0x6a, 0x0, 0x8b, 0x7a, 0x2, 0x8d, 0x68, 0x67, 0xe3, 0xa, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char close_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x67, 0xdb, 0x58, 0xd0, 0xd3, 0xf0, 0xa3, 0x7c, 0x36, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x85, 0x14, 0x81, 0xf, 0x2c, 0x28, 0xe0, 0xda, 0xd5, 0x8c, 0x4e, 0x77, 0xb, 0xfc, 0xd5, 0x98, 0xd9, 0x20, 0x29, 0x7a, 0xb9, 0xa4, 0x68, 0x66, 0x83, 0xb, 0x93, 0xcc, 0x24, 0xa7, 0x9a, 0x44, 0x52, 0x24, 0x39, 0x91, 0xcc, 0x55, 0x89, 0xa4, 0xde, 0xcc, 0xce, 0x24, 0xb, 0xc9, 0x39, 0x84, 0xb0, 0xf7, 0xb2, 0xae, 0xeb, 0x76, 0xde, 0x8a, 0x4f, 0x92, 0x66, 0xd8, 0x91, 0x5c, 0x49, 0x5e, 0x9a, 0xe1, 0xb5, 0x64, 0x5, 0x16, 0x92, 0x8b, 0x7, 0x6f, 0x9b, 0x8c, 0x0, 0x4a, 0x29, 0x9b, 0x26, 0x81, 0xa4, 0x3e, 0xa5, 0x34, 0x2, 0x38, 0x2, 0x58, 0x0, 0xcc, 0x0, 0xe, 0x39, 0xe7, 0xd3, 0xfa, 0xb0, 0xee, 0xea, 0x8f, 0x7, 0x7b, 0xf5, 0x9d, 0xb7, 0xb0, 0x97, 0x55, 0x25, 0x5f, 0x17, 0xe9, 0x2e, 0xf9, 0xb8, 0xca, 0x3f, 0x9b, 0x1b, 0x1a, 0xe3, 0x40, 0x47, 0xa0, 0xda, 0xda, 0x61, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char close_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x67, 0xdb, 0x58, 0xd0, 0xd3, 0xf0, 0xa3, 0x7c, 0x36, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x85, 0x14, 0x81, 0xf, 0x2c, 0x28, 0xe0, 0xda, 0xd5, 0x8c, 0x4e, 0x77, 0xb, 0xfc, 0xd5, 0x98, 0xd9, 0x20, 0x29, 0x7a, 0xb9, 0xa4, 0x68, 0x66, 0x83, 0xb, 0x93, 0xcc, 0x24, 0xa7, 0x9a, 0x44, 0x52, 0x24, 0x39, 0x91, 0xcc, 0x55, 0x89, 0xa4, 0xde, 0xcc, 0xce, 0x24, 0xb, 0xc9, 0x39, 0x84, 0xb0, 0xf7, 0xb2, 0xae, 0xeb, 0x76, 0xde, 0x8a, 0x4f, 0x92, 0x66, 0xd8, 0x91, 0x5c, 0x49, 0x5e, 0x9a, 0xe1, 0xb5, 0x64, 0x5, 0x16, 0x92, 0x8b, 0x7, 0x6f, 0x9b, 0x8c, 0x0, 0x4a, 0x29, 0x9b, 0x26, 0x81, 0xa4, 0x3e, 0xa5, 0x34, 0x2, 0x38, 0x2, 0x58, 0x0, 0xcc, 0x0, 0xe, 0x39, 0xe7, 0xd3, 0xfa, 0xb0, 0xee, 0xea, 0x8f, 0x7, 0x7b, 0xf5, 0x9d, 0xb7, 0xb0, 0x97, 0x55, 0x25, 0x5f, 0x17, 0xe9, 0x2e, 0xf9, 0xb8, 0xca, 0x3f, 0x9b, 0x1b, 0x1a, 0xe3, 0x40, 0x47, 0xa0, 0xda, 0xda, 0x61, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char color_picker_hue_png[] = { @@ -59,31 +59,31 @@ static const unsigned char color_picker_hue_png[] = { }; static const unsigned char color_picker_sample_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x2, 0x0, 0x0, 0x0, 0xed, 0x20, 0x74, 0x8, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x9, 0x18, 0xc, 0x27, 0x37, 0x29, 0x4f, 0x42, 0x2d, 0x0, 0x0, 0x0, 0x61, 0x49, 0x44, 0x41, 0x54, 0x68, 0xde, 0xed, 0xd9, 0xb1, 0xd, 0x0, 0x21, 0xc, 0x3, 0x40, 0x40, 0xbf, 0x5f, 0x66, 0xcd, 0x84, 0xf9, 0x96, 0x19, 0xf0, 0x5d, 0x87, 0x5c, 0x5b, 0x9, 0xca, 0x9e, 0x99, 0x75, 0xe9, 0xee, 0xfb, 0x59, 0x55, 0x52, 0xe9, 0xc3, 0xe9, 0x59, 0x10, 0x4c, 0x1, 0x50, 0x0, 0x50, 0x0, 0x8, 0xf4, 0xf9, 0x15, 0x49, 0x93, 0x53, 0x13, 0x0, 0x2b, 0x10, 0x28, 0x0, 0x28, 0x0, 0x64, 0xd9, 0x2e, 0xc1, 0xd2, 0xe4, 0xd4, 0x4, 0xc0, 0xa, 0x4, 0xa, 0x0, 0xa, 0x0, 0x59, 0x5c, 0x82, 0xa5, 0xd1, 0xa9, 0x9, 0x80, 0x15, 0x8, 0x14, 0x0, 0x14, 0x0, 0xb2, 0xfc, 0x5b, 0xb2, 0x3c, 0x5a, 0x4, 0xa1, 0xf3, 0x57, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x14, 0x8, 0x0, 0x0, 0x0, 0x0, 0x47, 0x29, 0xbc, 0x83, 0x0, 0x0, 0x0, 0x3c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xd5, 0x21, 0x11, 0x0, 0x30, 0xc, 0x4, 0xc1, 0xfa, 0x57, 0x53, 0x87, 0xed, 0x4, 0x45, 0xc4, 0xed, 0xa3, 0xc3, 0x4b, 0xfe, 0xbc, 0xd9, 0x9d, 0x35, 0x2b, 0xe, 0x0, 0x0, 0x0, 0x80, 0xed, 0x66, 0xc5, 0x1, 0x0, 0x0, 0x0, 0xe0, 0x6, 0x1, 0x0, 0x0, 0x90, 0x6, 0x70, 0x83, 0x0, 0x0, 0x0, 0x28, 0x3, 0x7c, 0x54, 0x93, 0xd6, 0xf1, 0xd1, 0x16, 0x8a, 0x17, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char dosfont_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x0, 0xeb, 0x45, 0x5c, 0x66, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x1, 0xdd, 0x8a, 0x13, 0xa4, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x89, 0x0, 0x0, 0xb, 0x89, 0x1, 0x37, 0xc9, 0xcb, 0xad, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x2, 0x83, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0xd4, 0xb1, 0x6e, 0xdb, 0x30, 0x10, 0x0, 0x50, 0x22, 0x3, 0x27, 0x22, 0xc8, 0x78, 0x83, 0x91, 0xa9, 0x1f, 0xc0, 0xa9, 0x10, 0xa, 0x7e, 0xc, 0x11, 0x14, 0x87, 0xc, 0x1c, 0x32, 0x9, 0x1a, 0xe, 0x46, 0xa6, 0xfc, 0x43, 0xff, 0x86, 0xb5, 0x80, 0x9b, 0x88, 0x8e, 0x5d, 0x64, 0x18, 0x9e, 0xdc, 0xd5, 0x53, 0x91, 0xc1, 0xa0, 0x7a, 0xa4, 0xe4, 0xd4, 0x31, 0xd2, 0x25, 0x70, 0x97, 0xa2, 0x37, 0x48, 0xe6, 0x33, 0x45, 0xdd, 0x51, 0x24, 0x95, 0x7a, 0x23, 0xe0, 0x75, 0x13, 0xb, 0xd8, 0x93, 0xbf, 0x51, 0x51, 0xa3, 0xac, 0x99, 0xc9, 0x29, 0x87, 0x81, 0x83, 0xb2, 0x0, 0xc7, 0xfe, 0xee, 0x43, 0x58, 0x85, 0x95, 0xb7, 0xa6, 0xb6, 0xaf, 0x7a, 0xe9, 0x93, 0x63, 0xc3, 0xf2, 0xc, 0x96, 0x3e, 0xba, 0x97, 0x11, 0x3, 0xb5, 0x46, 0xc0, 0x15, 0x30, 0x43, 0x1, 0xbd, 0x6, 0x81, 0x71, 0xa9, 0xb2, 0x82, 0x9, 0x92, 0x3d, 0xf6, 0xb0, 0xbd, 0x5c, 0xf2, 0x53, 0xf2, 0x75, 0xc, 0x11, 0x5f, 0xc7, 0xe0, 0xc4, 0xaa, 0xb4, 0x40, 0x41, 0xc4, 0x69, 0xd0, 0x27, 0x55, 0x12, 0x13, 0x78, 0x74, 0xa7, 0xb5, 0xd8, 0x3f, 0x14, 0x77, 0x81, 0x0, 0x22, 0x93, 0x9b, 0x4c, 0x54, 0x5b, 0x72, 0x6d, 0x98, 0x17, 0xd1, 0x33, 0xb3, 0x94, 0xaa, 0x3c, 0x93, 0xea, 0xb4, 0x76, 0x31, 0x6a, 0x66, 0x0, 0xa9, 0x59, 0x1c, 0x8c, 0xe, 0x33, 0xc0, 0x12, 0x4c, 0x29, 0xc2, 0xa5, 0xc3, 0xc1, 0xd0, 0xb2, 0x64, 0x6a, 0x60, 0xa3, 0xc0, 0xea, 0xac, 0x19, 0x58, 0x4b, 0xa9, 0x4a, 0x17, 0xf0, 0xda, 0x68, 0xb6, 0x5, 0xec, 0xb2, 0xf6, 0x88, 0x33, 0xc8, 0x18, 0x52, 0xd5, 0x5a, 0x1, 0xb3, 0x61, 0x1, 0x53, 0xdf, 0x2, 0x51, 0x2d, 0x33, 0xdd, 0x12, 0x59, 0xea, 0x94, 0x95, 0x3c, 0x80, 0x2e, 0x5e, 0xf9, 0xdb, 0x71, 0x73, 0x70, 0xcf, 0x39, 0x3b, 0x76, 0xb7, 0xbb, 0x7d, 0xcf, 0x74, 0x50, 0xd, 0x62, 0x40, 0x44, 0x6, 0x83, 0xfe, 0xc7, 0x8e, 0x51, 0x5, 0x5c, 0xe1, 0xdd, 0xdd, 0xaa, 0xc2, 0xf8, 0x53, 0x80, 0x31, 0xe2, 0xfd, 0x7d, 0x14, 0x8, 0x7e, 0xcc, 0x5, 0x28, 0x62, 0xd7, 0xc5, 0xc, 0xa6, 0xf3, 0xc3, 0x46, 0xa6, 0x30, 0xd7, 0x1e, 0x1b, 0x2e, 0xd0, 0x7f, 0x63, 0x5f, 0x1f, 0xf1, 0x32, 0xc9, 0x90, 0x82, 0xef, 0xb9, 0x82, 0xc, 0x5a, 0x1, 0xef, 0x66, 0x90, 0xd7, 0x7a, 0x2c, 0x80, 0x13, 0x94, 0xc4, 0xf6, 0x9f, 0xd8, 0x75, 0xbb, 0x2c, 0x89, 0xed, 0xff, 0x42, 0xe9, 0xa7, 0xfb, 0xa4, 0x84, 0xec, 0x13, 0x45, 0x7, 0x1a, 0xb9, 0x97, 0x18, 0x65, 0xab, 0x4, 0xf9, 0x54, 0x8c, 0x3c, 0x54, 0xe8, 0xed, 0xa3, 0x7c, 0x7b, 0x55, 0xe0, 0x8b, 0x0, 0xf6, 0x4f, 0x36, 0xd6, 0x3d, 0xc3, 0xe8, 0x41, 0xc0, 0xa1, 0xb1, 0xdb, 0x9, 0xa8, 0x29, 0x0, 0xe, 0xec, 0xc3, 0x4, 0xc1, 0x8, 0xc, 0x0, 0xd6, 0x36, 0xf3, 0x23, 0xba, 0x80, 0x3, 0x6f, 0x17, 0x15, 0xbe, 0x4b, 0xe5, 0x8c, 0x23, 0xc2, 0x57, 0x7b, 0x5d, 0x61, 0x53, 0xc0, 0x61, 0xf, 0xbd, 0xd5, 0x15, 0x68, 0x47, 0x8e, 0x0, 0x7b, 0x37, 0xba, 0xab, 0xba, 0x59, 0xcc, 0x79, 0x3d, 0xd7, 0xaf, 0x5a, 0xe3, 0x85, 0x66, 0x69, 0xab, 0x16, 0x32, 0x31, 0x5b, 0xd0, 0xdb, 0x66, 0x2, 0x2f, 0x6f, 0xe, 0xb2, 0x42, 0xb5, 0x87, 0xdf, 0xf0, 0x59, 0xae, 0x6a, 0x86, 0xae, 0x93, 0x4c, 0x7d, 0x1b, 0x9a, 0x6b, 0x84, 0xdd, 0x9a, 0xd6, 0xca, 0xc8, 0x89, 0xc3, 0xfb, 0xd4, 0x82, 0xe, 0x30, 0xa2, 0x2c, 0x18, 0xc2, 0x98, 0xb2, 0x4f, 0x8, 0xba, 0x83, 0xa1, 0x40, 0x12, 0x88, 0x6f, 0x43, 0x38, 0x82, 0x1c, 0x1f, 0x15, 0x70, 0x82, 0x96, 0xa8, 0xa5, 0x3d, 0xed, 0x9c, 0xde, 0xb9, 0x1, 0xe9, 0xb8, 0x5f, 0x4c, 0x39, 0xd2, 0xa6, 0xac, 0xa6, 0x48, 0xe7, 0xd0, 0x95, 0x53, 0xb0, 0xc4, 0x7b, 0x97, 0xd4, 0xcd, 0x3c, 0xdd, 0xf0, 0xd0, 0x4e, 0xbf, 0xe6, 0x65, 0x24, 0x5b, 0x7b, 0x7d, 0xe, 0xe5, 0xd6, 0xae, 0xe9, 0x90, 0x64, 0xfd, 0x70, 0x9e, 0x21, 0xb5, 0x6c, 0x5, 0xa4, 0xa2, 0x87, 0xe9, 0xa3, 0x25, 0xf4, 0x5, 0x5c, 0x39, 0x61, 0xa6, 0x1e, 0xbe, 0x11, 0x18, 0x80, 0xed, 0xb, 0x18, 0x9b, 0x70, 0x70, 0xec, 0x5f, 0x80, 0x3f, 0x26, 0x27, 0xb3, 0xc9, 0x33, 0xc8, 0x5c, 0x2c, 0x5a, 0x59, 0x1f, 0xcb, 0x2c, 0x89, 0x9d, 0xae, 0xf, 0x7d, 0xcc, 0xdb, 0x9c, 0xdd, 0xd5, 0xed, 0x7c, 0x7f, 0xbe, 0xd0, 0x52, 0xf9, 0x1f, 0xff, 0x76, 0xfc, 0x2, 0x24, 0x3a, 0x65, 0x42, 0xf6, 0x41, 0x91, 0x95, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x1, 0x0, 0x0, 0x0, 0x0, 0xeb, 0x45, 0x5c, 0x66, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x2, 0x64, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xbc, 0xd4, 0x81, 0x86, 0x2c, 0x47, 0x14, 0xc6, 0xf1, 0xcf, 0x45, 0x81, 0x32, 0x2, 0x38, 0x58, 0x17, 0xe4, 0x1, 0xa, 0x44, 0x8b, 0x7a, 0x98, 0xb2, 0xe2, 0xb8, 0x28, 0x2c, 0x68, 0x8d, 0x63, 0x5c, 0xb0, 0xef, 0x90, 0xb7, 0xe9, 0x6c, 0x71, 0x40, 0x9, 0x20, 0xd0, 0x63, 0x2d, 0x98, 0x0, 0xc, 0x88, 0x60, 0x54, 0xa7, 0xaa, 0xba, 0xef, 0x66, 0x67, 0x5d, 0x10, 0x37, 0xf7, 0xf, 0xc3, 0x4f, 0x39, 0x53, 0x87, 0xd2, 0xf8, 0x5a, 0x84, 0x9b, 0xb8, 0x81, 0xc3, 0x6b, 0xc4, 0x90, 0x1, 0xce, 0xee, 0xe4, 0xe1, 0x39, 0x6a, 0x84, 0x23, 0xda, 0x80, 0xe1, 0x7f, 0x8c, 0x4f, 0xf1, 0x29, 0x38, 0x8b, 0xd6, 0x87, 0x4, 0x8f, 0x32, 0xf, 0xa, 0x67, 0x99, 0x2a, 0x98, 0x4, 0x42, 0x94, 0xd1, 0x56, 0xf0, 0xd, 0xec, 0xd2, 0xc0, 0x9c, 0xa8, 0xc2, 0x7a, 0x44, 0x1, 0x6d, 0x90, 0xdd, 0x97, 0x13, 0x2e, 0x1, 0x28, 0x8f, 0x39, 0xf4, 0x19, 0x55, 0x42, 0x9f, 0xa1, 0x59, 0x41, 0x4, 0x10, 0x68, 0xe6, 0x6d, 0xe8, 0x23, 0xac, 0xeb, 0xf0, 0xd9, 0xbf, 0xdd, 0xc5, 0xdd, 0x2c, 0xf7, 0x4d, 0x23, 0x11, 0x5b, 0x86, 0x22, 0x82, 0x96, 0x0, 0x83, 0xea, 0xdd, 0x1c, 0x54, 0x15, 0x30, 0x8, 0x2a, 0x98, 0x8c, 0xf1, 0xf3, 0x6c, 0x54, 0x89, 0x2c, 0x5c, 0x75, 0xb2, 0x26, 0xee, 0x40, 0x47, 0xb2, 0x15, 0xc8, 0xe7, 0xeb, 0xd5, 0xca, 0x11, 0x70, 0xb0, 0xf4, 0xc, 0x72, 0xa6, 0x18, 0x25, 0x35, 0x40, 0x80, 0x69, 0x10, 0x8c, 0x35, 0xea, 0x1a, 0xb8, 0xa3, 0x6d, 0x30, 0xef, 0x40, 0x44, 0x20, 0x9c, 0x40, 0xaa, 0x56, 0x2b, 0xd8, 0xfe, 0x2f, 0x34, 0xe3, 0x58, 0xe4, 0xa3, 0x88, 0x93, 0x9, 0xce, 0x20, 0x90, 0xe0, 0xfb, 0xf4, 0xc3, 0xd5, 0xff, 0x5d, 0x8a, 0x57, 0xff, 0xf1, 0x7c, 0x49, 0x2a, 0x57, 0xc, 0xcc, 0x91, 0x99, 0x95, 0x2c, 0x87, 0x3f, 0xcf, 0xca, 0x88, 0xfc, 0xc4, 0xf7, 0xf7, 0x4f, 0x1d, 0xd6, 0xbf, 0x2a, 0x28, 0xcf, 0xfc, 0xe9, 0xd3, 0x5c, 0x21, 0x86, 0xb5, 0x34, 0x90, 0x99, 0xa7, 0x69, 0x2e, 0x64, 0xa7, 0xb0, 0x3c, 0xab, 0xa0, 0xf4, 0x13, 0xcf, 0xda, 0x20, 0xfd, 0xae, 0x1, 0x5a, 0x21, 0x4, 0x55, 0xca, 0x31, 0x24, 0x6d, 0xd0, 0x86, 0x76, 0xe0, 0xfb, 0x1d, 0x38, 0x72, 0xe0, 0x6, 0xbc, 0x41, 0xbb, 0xd8, 0xe5, 0x67, 0xf5, 0xd3, 0xb9, 0x24, 0x95, 0xcb, 0xff, 0xb0, 0x3a, 0xdc, 0x2d, 0xc, 0x15, 0xe4, 0x2a, 0xab, 0xa6, 0xda, 0xea, 0xe1, 0x23, 0x8, 0xca, 0xba, 0x74, 0x48, 0xee, 0xb3, 0x55, 0xa0, 0xc1, 0xaf, 0x15, 0x38, 0x3d, 0xba, 0xd9, 0xa2, 0x43, 0xa0, 0xa, 0x9e, 0xad, 0x7b, 0xd9, 0x40, 0x86, 0x6, 0xe4, 0xc9, 0x3d, 0x6c, 0x10, 0x6d, 0x85, 0x85, 0xc8, 0xb9, 0x61, 0x3, 0x36, 0xd, 0x3c, 0x5, 0x77, 0xd7, 0xe1, 0xf, 0x56, 0x52, 0x5e, 0x99, 0x7e, 0x73, 0x87, 0xe, 0xcf, 0xd, 0x3c, 0x27, 0x4a, 0xce, 0x74, 0x90, 0xb3, 0x78, 0x21, 0x4e, 0x7e, 0xf5, 0x1f, 0x7c, 0x83, 0xaa, 0xb7, 0x1d, 0xf0, 0xb6, 0x15, 0xdf, 0xa6, 0x17, 0xdc, 0x61, 0xc0, 0xb, 0x99, 0x97, 0x61, 0x83, 0x0, 0x8b, 0x88, 0x40, 0x26, 0xd0, 0xbf, 0xf0, 0xb, 0x2, 0xb0, 0xc3, 0x34, 0x89, 0x97, 0x30, 0xc6, 0xe1, 0xc0, 0x74, 0x3e, 0xc9, 0x9, 0x36, 0x6a, 0xd4, 0x4b, 0x1e, 0xc9, 0x44, 0x5a, 0x59, 0x19, 0xc2, 0x73, 0x2e, 0x21, 0x33, 0x99, 0x89, 0x96, 0x6, 0xb9, 0xc2, 0xfc, 0x75, 0x88, 0x5f, 0x40, 0xb3, 0x76, 0xe0, 0xd, 0x46, 0x91, 0x51, 0x2e, 0x72, 0xf6, 0xe6, 0xec, 0x17, 0x16, 0xc1, 0x96, 0x5, 0x18, 0xad, 0xb0, 0x43, 0x7e, 0xf, 0x13, 0xe0, 0xd1, 0xba, 0xfc, 0xe7, 0x77, 0xd3, 0x3b, 0xd0, 0xc3, 0x78, 0xf3, 0xb9, 0x22, 0xa2, 0xd3, 0x7b, 0x40, 0x6d, 0x3c, 0xc9, 0x35, 0xa7, 0x94, 0xb4, 0xec, 0x90, 0x47, 0x75, 0x15, 0x58, 0xf3, 0x3, 0xe, 0x1d, 0x38, 0x34, 0xf0, 0x4a, 0xb5, 0xe, 0x61, 0xa8, 0xb0, 0x90, 0xba, 0x57, 0xb0, 0x2e, 0xf3, 0xe2, 0x35, 0xbc, 0x82, 0xfe, 0x94, 0xfd, 0xca, 0xaa, 0x3b, 0xc8, 0x45, 0xee, 0x46, 0xe2, 0x74, 0x2c, 0xf5, 0x62, 0x6f, 0xdf, 0x87, 0xc1, 0x9e, 0x7d, 0xf7, 0xfb, 0xcf, 0x18, 0xe4, 0xa0, 0xf4, 0xf, 0x22, 0x3c, 0x3d, 0xa, 0x46, 0x1, 0x0, 0x24, 0x3a, 0x65, 0x42, 0x42, 0xc7, 0x4f, 0x7c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char dropdown_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x5, 0x1f, 0x98, 0x19, 0x18, 0x18, 0x3f, 0x30, 0xff, 0xd3, 0x83, 0x70, 0xff, 0x33, 0x33, 0x30, 0x8, 0x9f, 0x61, 0xf9, 0x6b, 0xff, 0x65, 0x2f, 0x3, 0x1c, 0xbc, 0xea, 0x66, 0x62, 0xbc, 0xcf, 0xc0, 0xc0, 0xf0, 0x7, 0x26, 0xc0, 0x74, 0x89, 0x89, 0xe9, 0x29, 0x9f, 0x14, 0x3, 0xb, 0xc3, 0x5f, 0x6, 0x6, 0x6, 0x6, 0xee, 0x38, 0x91, 0x25, 0xc, 0xc, 0xc, 0x1f, 0xd8, 0xde, 0x4b, 0x3e, 0xfc, 0xff, 0xf0, 0xff, 0x9b, 0x58, 0xb8, 0xce, 0xf, 0x6c, 0xef, 0xe4, 0xde, 0xa4, 0x32, 0x20, 0x83, 0xf, 0x4c, 0x30, 0x16, 0x0, 0x75, 0xad, 0x1b, 0x7f, 0x65, 0xec, 0x78, 0x4c, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x2, 0x60, 0x16, 0x98, 0x78, 0x67, 0x8, 0x81, 0x6f, 0x4d, 0xde, 0x9a, 0x0, 0x5, 0xde, 0x3a, 0x3d, 0xfc, 0x8f, 0x80, 0xaf, 0xba, 0x18, 0xde, 0x29, 0x2, 0x19, 0xbf, 0x61, 0x2, 0x6f, 0x62, 0x18, 0x3e, 0xb0, 0xbd, 0x97, 0x4, 0x32, 0xff, 0x80, 0xb9, 0xb1, 0x20, 0x93, 0xc0, 0x42, 0x8, 0x2e, 0x54, 0xe8, 0x9d, 0xdc, 0x9b, 0x54, 0x10, 0xb, 0x21, 0xc4, 0x4, 0x63, 0x1, 0x0, 0x86, 0x1f, 0x3b, 0x1e, 0x92, 0x22, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char error_icon_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x4, 0x0, 0x0, 0x0, 0xd9, 0x73, 0xb2, 0x7f, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x5d, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xed, 0x94, 0xc1, 0xe, 0x80, 0x20, 0xc, 0x43, 0x5b, 0xe3, 0xff, 0xff, 0x72, 0x3d, 0xcc, 0x85, 0xa1, 0xbb, 0x18, 0xf4, 0x62, 0xca, 0xa9, 0x74, 0xe3, 0x65, 0xd, 0x1, 0xa, 0x6b, 0x6b, 0x5b, 0x3c, 0x6f, 0x80, 0x1, 0x7f, 0x1, 0xec, 0x29, 0x78, 0xbe, 0x2a, 0x31, 0x94, 0x98, 0x9e, 0x98, 0xf5, 0xab, 0x37, 0x1, 0xaa, 0x19, 0x8d, 0xe2, 0x50, 0xb1, 0x9b, 0xbd, 0xb7, 0x23, 0x8c, 0x21, 0x7b, 0xd5, 0xf5, 0x3d, 0x88, 0x50, 0x1, 0xdf, 0x46, 0xb8, 0xf, 0x5c, 0xef, 0xa6, 0xab, 0xd1, 0x7f, 0xa2, 0x1, 0x6, 0x0, 0x0, 0xe, 0x62, 0x6, 0x31, 0x47, 0xb6, 0x7f, 0xdd, 0x14, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x4, 0x0, 0x0, 0x0, 0xd9, 0x73, 0xb2, 0x7f, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x36, 0x18, 0x5, 0xa3, 0x60, 0x14, 0xfc, 0x87, 0x40, 0x38, 0xb, 0x21, 0x6, 0x6, 0x18, 0x62, 0x98, 0x6, 0xa0, 0xb1, 0xfe, 0xe3, 0x67, 0xd1, 0xc2, 0x0, 0x10, 0xc4, 0xc5, 0x82, 0x91, 0x43, 0xc0, 0xb, 0xb8, 0x15, 0x63, 0x78, 0x6, 0x5, 0x8c, 0x82, 0x51, 0x30, 0xa, 0x0, 0x35, 0xa3, 0x4c, 0xb4, 0x7c, 0x8a, 0x7, 0x6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xb9, 0xa2, 0x9b, 0xc9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char frame_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xcc, 0x40, 0x27, 0xb9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x88, 0x5, 0x1d, 0x48, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x4, 0x3, 0x0, 0x0, 0x0, 0xa4, 0x5b, 0x41, 0xd4, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0x47, 0x8c, 0xbf, 0xff, 0xff, 0xff, 0xcc, 0x40, 0x27, 0xb9, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe, 0x39, 0x68, 0x7a, 0x7b, 0x3a, 0x74, 0x10, 0x8, 0x69, 0xf, 0x6, 0x75, 0x11, 0xb8, 0x16, 0x0, 0x1, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x10, 0x32, 0x9, 0xd, 0x75, 0x56, 0x64, 0x48, 0xef, 0x9c, 0x39, 0x73, 0x46, 0x19, 0xc3, 0x6a, 0x6, 0x20, 0xd8, 0xc5, 0x10, 0x3, 0xa2, 0x8e, 0x32, 0x44, 0x82, 0xa8, 0xa9, 0xd8, 0x29, 0xa8, 0x12, 0xb0, 0x6, 0x29, 0x86, 0xdc, 0x9d, 0x33, 0x67, 0xce, 0x2b, 0x63, 0x10, 0x3, 0x1b, 0x6, 0x0, 0xdf, 0xc6, 0x11, 0x6d, 0xb8, 0xf4, 0x9c, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char full_panel_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x44, 0xa4, 0x8a, 0xc6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0x26, 0x26, 0x28, 0x25, 0x25, 0x27, 0x24, 0x24, 0x26, 0x23, 0x23, 0x25, 0x22, 0x22, 0x24, 0x21, 0x21, 0x23, 0x1e, 0x1e, 0x20, 0x1d, 0x1d, 0x1f, 0x1c, 0x1c, 0x1e, 0x31, 0x30, 0x32, 0x50, 0x4e, 0x54, 0x4e, 0x4c, 0x50, 0x4c, 0x4a, 0x4e, 0x3d, 0x3b, 0x3f, 0x38, 0x36, 0x3a, 0xff, 0xff, 0xff, 0x4, 0xb3, 0x69, 0x9b, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x10, 0x95, 0xb2, 0xd, 0x2c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0xed, 0x93, 0x29, 0x12, 0xc0, 0x30, 0xc, 0xc4, 0x7c, 0x3b, 0x67, 0xf3, 0xff, 0xdf, 0xb6, 0xe1, 0xce, 0x98, 0x15, 0x45, 0x58, 0xb3, 0x68, 0x5, 0x0, 0x80, 0x48, 0x21, 0x88, 0xb0, 0x41, 0x62, 0x51, 0xb, 0x50, 0x61, 0xda, 0xa, 0xb1, 0x79, 0xa9, 0x1, 0xc5, 0x8d, 0xe9, 0x1b, 0x60, 0x6b, 0x7d, 0xcc, 0x80, 0xd1, 0x9b, 0x31, 0x2, 0x8a, 0xf7, 0x67, 0x85, 0x3c, 0xdd, 0x5, 0x81, 0xb4, 0x8c, 0x75, 0x60, 0x14, 0x25, 0x20, 0xab, 0xf3, 0x24, 0xcc, 0x6a, 0x57, 0xb8, 0xc2, 0xff, 0x42, 0x76, 0xda, 0xf4, 0xf6, 0x69, 0x38, 0x69, 0x7a, 0x79, 0xbc, 0x49, 0xfe, 0x2f, 0x65, 0xd3, 0x2d, 0x45, 0xb, 0x5e, 0xbc, 0x3b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x4, 0x3, 0x0, 0x0, 0x0, 0x81, 0x54, 0x67, 0xc7, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0x26, 0x26, 0x28, 0x25, 0x25, 0x27, 0x24, 0x24, 0x26, 0x23, 0x23, 0x25, 0x22, 0x22, 0x24, 0x21, 0x21, 0x23, 0x1e, 0x1e, 0x20, 0x1d, 0x1d, 0x1f, 0x1c, 0x1c, 0x1e, 0x31, 0x30, 0x32, 0x50, 0x4e, 0x54, 0x4e, 0x4c, 0x50, 0x4c, 0x4a, 0x4e, 0x3d, 0x3b, 0x3f, 0x38, 0x36, 0x3a, 0xb3, 0xde, 0x6f, 0x4d, 0x0, 0x0, 0x0, 0x5a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0x14, 0x52, 0x82, 0x3, 0x45, 0x1, 0x20, 0x5f, 0xd9, 0x35, 0xd, 0xe, 0x42, 0x8c, 0x4, 0x18, 0x98, 0xcc, 0x2a, 0x66, 0xc2, 0x41, 0x7b, 0xb2, 0x2, 0x83, 0x70, 0xd6, 0x9e, 0xbb, 0x70, 0x70, 0x7a, 0x99, 0x21, 0x83, 0x48, 0xf5, 0xfb, 0xff, 0x70, 0xf0, 0x6f, 0xbb, 0x23, 0x83, 0x6a, 0xcf, 0x7f, 0x24, 0x70, 0x22, 0x88, 0x41, 0x6d, 0x2e, 0xb2, 0xc0, 0xcd, 0x24, 0x8a, 0x5, 0x46, 0x5, 0x30, 0x2, 0x19, 0x23, 0x1a, 0x30, 0x22, 0xa, 0x23, 0x2a, 0x31, 0x22, 0x1b, 0x23, 0x39, 0x0, 0x0, 0x8c, 0xb1, 0x80, 0xd2, 0x41, 0x59, 0x8c, 0x74, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_png[] = { @@ -91,391 +91,395 @@ static const unsigned char graph_node_png[] = { }; static const unsigned char graph_node_breakpoint_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x6, 0xf, 0x3b, 0x1c, 0xec, 0x64, 0x51, 0x75, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x8f, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0xd7, 0xbd, 0x9, 0xc0, 0x20, 0x10, 0x5, 0xe0, 0x53, 0x2c, 0x5d, 0x40, 0x74, 0x4, 0xf7, 0x9f, 0xc4, 0x11, 0x22, 0x2e, 0x60, 0x6f, 0x9a, 0x13, 0x4e, 0x21, 0x41, 0x50, 0x48, 0x91, 0x77, 0x95, 0xf8, 0xf3, 0x79, 0x62, 0xf5, 0x88, 0x36, 0x4b, 0xf5, 0x41, 0x2d, 0xf1, 0x22, 0x22, 0xbf, 0x78, 0x2e, 0x5b, 0x97, 0x2, 0xc9, 0xc3, 0xc, 0x2c, 0x95, 0xdc, 0x6f, 0x78, 0xce, 0x5b, 0x97, 0xd4, 0x42, 0x27, 0xd9, 0xba, 0x14, 0xac, 0x4b, 0xa1, 0x96, 0xd8, 0x24, 0x20, 0x9f, 0x41, 0x1d, 0x7b, 0xba, 0x59, 0xb6, 0xaf, 0xa7, 0x3d, 0x7e, 0x78, 0xdb, 0x54, 0xbc, 0x36, 0x74, 0xa7, 0x77, 0x7f, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7e, 0x4, 0xe4, 0xb7, 0xfc, 0xc8, 0x6b, 0x59, 0xce, 0x99, 0x39, 0x95, 0x71, 0xb4, 0x6b, 0x4b, 0x89, 0xf5, 0x44, 0x72, 0x3d, 0x93, 0x9d, 0x3f, 0xad, 0x1b, 0x54, 0xed, 0x49, 0xd3, 0x36, 0x45, 0x4f, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x2, 0x3, 0x0, 0x0, 0x0, 0x6e, 0x13, 0x1f, 0x5, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf4, 0xe7, 0x2c, 0xf4, 0xe7, 0x2c, 0xec, 0x5a, 0x6b, 0x42, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe4, 0xd1, 0xf4, 0xeb, 0x59, 0x0, 0x0, 0x0, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x3, 0xb6, 0x55, 0xab, 0x26, 0x30, 0x88, 0x30, 0x0, 0x91, 0x42, 0xd6, 0x4a, 0xe, 0x6, 0x45, 0x7, 0x46, 0xf, 0x6, 0x25, 0x6, 0x86, 0xe, 0x20, 0x31, 0x4a, 0x80, 0x42, 0x3, 0x1c, 0x2e, 0xe0, 0x10, 0x82, 0x84, 0x15, 0x1c, 0x0, 0x0, 0x41, 0x2d, 0x2b, 0x21, 0xbb, 0xb7, 0x1a, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_close_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x93, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0x95, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x7b, 0xdb, 0x58, 0xa4, 0xa7, 0xe1, 0x47, 0xfe, 0x2c, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x15, 0xc9, 0x20, 0x1f, 0x52, 0xae, 0xdd, 0xd9, 0x2b, 0xe6, 0xe, 0x0, 0x60, 0x66, 0x59, 0x52, 0x82, 0x33, 0x92, 0x92, 0x99, 0x65, 0xec, 0x30, 0xc9, 0x4a, 0x72, 0x19, 0x95, 0x24, 0x25, 0x92, 0xb, 0xc9, 0x6a, 0x66, 0x19, 0x92, 0x26, 0x33, 0x7b, 0x92, 0x6c, 0x24, 0xd7, 0x10, 0xc2, 0xdc, 0xc1, 0x5f, 0x59, 0x8c, 0xf1, 0x32, 0xc, 0x42, 0x8, 0xb3, 0xb, 0x3b, 0xdb, 0xde, 0x24, 0x5f, 0x2e, 0xdc, 0x97, 0x3a, 0xb0, 0x91, 0xdc, 0x7e, 0xe1, 0xb3, 0x67, 0x66, 0x9f, 0xd6, 0xda, 0x69, 0x58, 0x90, 0x34, 0x95, 0x52, 0xee, 0x0, 0x6e, 0x0, 0x36, 0x0, 0x2b, 0x80, 0x6b, 0xad, 0xf5, 0xd1, 0x8b, 0x70, 0x6d, 0xb8, 0xf6, 0xfe, 0xd9, 0x18, 0x96, 0xe, 0x1f, 0xe, 0x38, 0xf6, 0x1a, 0x1f, 0x9f, 0xec, 0x40, 0x47, 0x56, 0x51, 0x84, 0x77, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x75, 0x90, 0xb5, 0x1, 0xc0, 0x30, 0x10, 0x3, 0x55, 0x1a, 0xbe, 0xc, 0x6e, 0xe6, 0xb5, 0xc3, 0x34, 0x4b, 0x98, 0xcc, 0xee, 0x7c, 0x4f, 0x92, 0x0, 0x70, 0x45, 0x19, 0x8c, 0x47, 0x19, 0x57, 0x37, 0x66, 0x1b, 0x6b, 0x74, 0x89, 0x32, 0xd6, 0xb0, 0xed, 0x2c, 0x51, 0xca, 0x6b, 0xb6, 0xb3, 0x41, 0x94, 0x0, 0xfe, 0x9f, 0x2c, 0x0, 0xa3, 0x64, 0x61, 0xa3, 0x6f, 0x66, 0xbd, 0xc6, 0x7f, 0xe9, 0x86, 0x3b, 0x5b, 0x34, 0x76, 0xa, 0xcf, 0xad, 0xe0, 0xaa, 0xbf, 0xa4, 0x4f, 0x5a, 0xa, 0x6d, 0x25, 0xba, 0x14, 0x37, 0x18, 0x8b, 0xe4, 0x0, 0x6f, 0xe9, 0x37, 0x83, 0x22, 0x73, 0x83, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_comment_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x19, 0x11, 0x2a, 0x1d, 0xd6, 0x78, 0x8b, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x1, 0x74, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x97, 0xbf, 0x4e, 0xc2, 0x50, 0x14, 0xc6, 0x7f, 0x6d, 0x91, 0x56, 0x1b, 0x90, 0x80, 0x2c, 0x44, 0xc2, 0xa0, 0x2e, 0xe, 0x3e, 0x3, 0x89, 0x93, 0xf1, 0x1d, 0x4c, 0x18, 0x4d, 0x1c, 0x7c, 0xb, 0x57, 0x7, 0x13, 0x47, 0x13, 0x77, 0x46, 0xe3, 0xc4, 0x4b, 0x98, 0x60, 0x4c, 0xd4, 0x81, 0x60, 0x58, 0x94, 0xff, 0x22, 0x2d, 0xd0, 0xd6, 0xe5, 0xde, 0x88, 0x8, 0x2, 0x35, 0x6e, 0xf7, 0x5b, 0x6e, 0x9a, 0x9c, 0xef, 0x77, 0xee, 0x39, 0x37, 0x1d, 0x3e, 0x8d, 0x2f, 0x69, 0x80, 0xe, 0x18, 0xe2, 0xd4, 0xf8, 0xae, 0x0, 0xf0, 0x1, 0x4f, 0x9c, 0x1, 0x63, 0x45, 0x3a, 0xb0, 0x6, 0x24, 0x81, 0x34, 0x10, 0x7, 0x56, 0x26, 0x0, 0x43, 0xa0, 0x3, 0xbc, 0x2, 0xd, 0xe0, 0x3, 0xf0, 0x65, 0x57, 0x1b, 0xd8, 0x5e, 0x8f, 0x25, 0x8e, 0x2d, 0xd3, 0x3a, 0x88, 0x46, 0xcd, 0x4d, 0xa6, 0x68, 0x30, 0x70, 0x5f, 0x1c, 0xd7, 0xb9, 0x6d, 0x77, 0x5b, 0x97, 0xc0, 0x13, 0xd0, 0xd3, 0x44, 0xa7, 0x5c, 0x32, 0x91, 0x3a, 0xdf, 0xca, 0xed, 0x1c, 0x16, 0x52, 0xdd, 0x2a, 0xbf, 0xe8, 0xaa, 0x1e, 0xcb, 0x3e, 0x57, 0x1e, 0x6f, 0x1a, 0xad, 0xfa, 0x29, 0x50, 0x91, 0x33, 0xa7, 0x4d, 0xd3, 0xca, 0xcf, 0x33, 0x3, 0x14, 0x52, 0xdd, 0xaa, 0x69, 0x5a, 0x79, 0x31, 0xaa, 0x21, 0x97, 0x65, 0x47, 0x8c, 0x88, 0xcd, 0x82, 0x12, 0xb5, 0x36, 0xa0, 0x49, 0x80, 0xc1, 0xf2, 0x32, 0x24, 0x20, 0x90, 0x4f, 0x12, 0x46, 0x3a, 0x7f, 0x94, 0x2, 0x28, 0x80, 0x2, 0x88, 0x5f, 0x7b, 0xfc, 0xe3, 0xec, 0xe1, 0x3d, 0x1b, 0x1a, 0x30, 0x1a, 0x7a, 0x1c, 0x65, 0xd8, 0x5f, 0xc4, 0x74, 0x5d, 0xa3, 0xa4, 0x5e, 0x41, 0x1, 0x14, 0x40, 0x1, 0x14, 0x40, 0x1, 0x14, 0x40, 0x1, 0xfe, 0x15, 0xa0, 0x4d, 0xc9, 0x88, 0x4b, 0xdf, 0xc0, 0xf, 0xe1, 0xf5, 0x25, 0xc0, 0x7, 0x1c, 0xcf, 0xf3, 0xdc, 0x45, 0x9d, 0xa2, 0xd6, 0x1, 0x7c, 0x5d, 0x44, 0xd9, 0xba, 0xe3, 0xf6, 0xcb, 0xc5, 0xa6, 0x5d, 0x9a, 0x67, 0x2e, 0x36, 0xed, 0x92, 0xe3, 0xf6, 0xcb, 0x40, 0x1d, 0xf0, 0x64, 0x72, 0x5d, 0x7, 0xf6, 0xe2, 0x76, 0xe2, 0xc2, 0x32, 0x57, 0x77, 0xd, 0xc3, 0xd0, 0x67, 0x74, 0xf6, 0x1d, 0xb7, 0x7f, 0xdf, 0xe9, 0xb5, 0x4e, 0x80, 0x3b, 0xa0, 0xad, 0x8d, 0x45, 0xb8, 0x38, 0x90, 0x1, 0x36, 0x0, 0x73, 0x46, 0xf8, 0x76, 0x81, 0x37, 0xa0, 0x26, 0x72, 0xb4, 0xa7, 0x4d, 0x2c, 0x34, 0x22, 0xf3, 0xe0, 0x8c, 0x9, 0x2, 0x31, 0xf2, 0x28, 0xe4, 0xe2, 0x7f, 0xea, 0x13, 0x64, 0x47, 0x6c, 0x83, 0x36, 0x6d, 0xd2, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x0, 0x78, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xd, 0x10, 0x17, 0x14, 0x18, 0x1d, 0x1a, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x12, 0x10, 0x13, 0x35, 0x2f, 0x38, 0x96, 0x42, 0x2b, 0x0, 0x0, 0x0, 0x19, 0x17, 0x1b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x77, 0x2f, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0xe, 0xb, 0x10, 0x24, 0x1e, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xb, 0x10, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x85, 0xbb, 0x9b, 0xdf, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x6, 0x8, 0x9, 0x2, 0xc, 0x1e, 0x33, 0x41, 0x46, 0xd, 0x31, 0x9a, 0xe3, 0xff, 0x5, 0x24, 0xb4, 0xff, 0xe2, 0x39, 0xf4, 0x44, 0xa, 0x47, 0xff, 0x42, 0x45, 0x3d, 0xf8, 0x2a, 0xcd, 0xff, 0x11, 0x3f, 0xd3, 0xfd, 0x2b, 0x31, 0x64, 0xfe, 0xeb, 0x0, 0x0, 0x0, 0x8d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xc8, 0x35, 0x62, 0x3, 0x41, 0x14, 0x4, 0xd1, 0xee, 0x21, 0x33, 0x33, 0xdb, 0xf7, 0xbf, 0x93, 0x99, 0x49, 0xcc, 0xd2, 0x7c, 0x2d, 0x53, 0xa6, 0x58, 0x5b, 0x59, 0x3d, 0x2, 0xc, 0x3, 0x20, 0x61, 0x20, 0x5c, 0x9, 0xc6, 0x74, 0x11, 0x20, 0x2c, 0x86, 0xbd, 0xec, 0x63, 0xa1, 0xd9, 0xa7, 0x47, 0x9a, 0x92, 0x7f, 0xda, 0x83, 0xa1, 0xcd, 0x60, 0xb2, 0xfa, 0xc7, 0x33, 0xf6, 0xb, 0xb0, 0x2e, 0xb4, 0xce, 0x2e, 0x17, 0x20, 0x2f, 0x82, 0x5d, 0x66, 0x2f, 0xb2, 0x20, 0xd4, 0x50, 0xc3, 0x19, 0x59, 0x1, 0xe3, 0xb, 0xa0, 0xa6, 0x34, 0xe7, 0x9c, 0x65, 0xa0, 0xe5, 0x9d, 0x7b, 0x3b, 0xe4, 0x38, 0x79, 0x27, 0xd2, 0xa2, 0xbb, 0x22, 0xd9, 0x8b, 0x7e, 0x43, 0x44, 0x5e, 0x8, 0x75, 0x67, 0x66, 0x1f, 0x3b, 0x0, 0x5a, 0x67, 0x7a, 0xfa, 0xe0, 0x9, 0xb8, 0x99, 0x3a, 0x44, 0xd8, 0xaf, 0xd7, 0x63, 0x10, 0x95, 0xe6, 0x1e, 0x57, 0xc1, 0x90, 0xf7, 0xdc, 0x9d, 0x9f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_comment_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf9, 0x43, 0xbb, 0x7f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x9, 0x2, 0xe, 0x16, 0x22, 0xbe, 0xef, 0xc2, 0xe1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x1, 0x4a, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0xd7, 0xbf, 0x4b, 0xdb, 0x41, 0x1c, 0xc6, 0xf1, 0xd7, 0x37, 0x51, 0x4, 0x3, 0xa, 0xa2, 0x20, 0xd2, 0xe2, 0xe2, 0x64, 0x41, 0xdc, 0xdc, 0xac, 0xe0, 0x54, 0xdc, 0xb2, 0xe6, 0x2f, 0x10, 0x1a, 0xf0, 0x4f, 0x11, 0x22, 0xf8, 0x17, 0x64, 0xcd, 0x26, 0x9d, 0x1c, 0x74, 0x73, 0x13, 0x21, 0x4e, 0x2e, 0xa5, 0xa5, 0x14, 0xac, 0x82, 0x82, 0x62, 0xd0, 0x7c, 0xd3, 0xa1, 0x77, 0x18, 0x35, 0xfe, 0x48, 0xa4, 0xdb, 0x3d, 0x70, 0xdc, 0xf2, 0x79, 0xde, 0x77, 0xf7, 0x39, 0x38, 0xee, 0xc9, 0xdc, 0x2b, 0x43, 0x1, 0xc5, 0x30, 0x67, 0x1e, 0xaa, 0x83, 0x1c, 0xed, 0x30, 0x77, 0x74, 0x15, 0x15, 0x30, 0x8a, 0x9, 0x4c, 0x61, 0xc, 0xc3, 0x8f, 0x0, 0xb7, 0xb8, 0xc4, 0x29, 0xce, 0x71, 0x8d, 0x3c, 0xae, 0x5a, 0xc2, 0x5c, 0xa3, 0x5a, 0x59, 0xc7, 0x17, 0x7c, 0xd0, 0x5b, 0x3f, 0xf1, 0xad, 0x5c, 0xab, 0x6f, 0xe3, 0x4, 0x57, 0x59, 0x58, 0x69, 0xb6, 0x51, 0xad, 0x6c, 0x62, 0xed, 0x77, 0xf3, 0xf0, 0x87, 0x17, 0x34, 0xfd, 0x69, 0xf1, 0x23, 0x76, 0xca, 0xb5, 0xfa, 0x6, 0xbe, 0xc7, 0x33, 0x4f, 0x61, 0xe5, 0x35, 0x33, 0x84, 0x9a, 0x95, 0xe0, 0x29, 0xc6, 0x66, 0x95, 0xc2, 0x78, 0xab, 0x62, 0x7d, 0x16, 0x1, 0x45, 0xfd, 0xab, 0x18, 0x1, 0x9d, 0x78, 0x25, 0x83, 0xa8, 0xe0, 0x9d, 0x4a, 0x80, 0x4, 0x48, 0x80, 0x7f, 0x1a, 0xea, 0xf1, 0xda, 0xc, 0xe, 0x38, 0xd8, 0xdf, 0x5b, 0x7d, 0x8b, 0x69, 0x69, 0xf9, 0xf3, 0x6e, 0xba, 0x85, 0x4, 0x48, 0x80, 0x4, 0x48, 0x80, 0x4, 0x48, 0x80, 0x4, 0xf8, 0xaf, 0x80, 0xac, 0x47, 0x46, 0xec, 0x7b, 0x7, 0xf9, 0x0, 0xde, 0x3c, 0x2, 0x72, 0xdc, 0xa0, 0xd5, 0x87, 0xb9, 0x15, 0x3c, 0x79, 0x21, 0x44, 0xd9, 0x33, 0x34, 0xbb, 0x3f, 0x4f, 0xaf, 0x7c, 0xb0, 0x9a, 0xc1, 0xd3, 0x8e, 0xc9, 0x75, 0x1c, 0xb, 0x8d, 0x6a, 0x65, 0xb, 0xf3, 0x2f, 0x34, 0x37, 0xc7, 0x71, 0xb9, 0x56, 0xff, 0x8a, 0x23, 0x5c, 0x64, 0x5d, 0x11, 0x6e, 0xc, 0x33, 0x98, 0xc4, 0xc8, 0x33, 0xe1, 0xbb, 0x85, 0x3f, 0xf8, 0x15, 0x72, 0x74, 0x3b, 0x7b, 0xd4, 0xd0, 0xa1, 0x98, 0x7, 0x9f, 0xd9, 0x41, 0x27, 0x1c, 0xf9, 0x6e, 0xc0, 0xc6, 0x3f, 0xd5, 0x5f, 0x9d, 0x54, 0x4e, 0x15, 0xfd, 0xeb, 0xb4, 0x4f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x0, 0x6f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x96, 0x42, 0x2b, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77, 0x2f, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xae, 0x6d, 0x5b, 0xae, 0x6d, 0x5b, 0x0, 0x0, 0x0, 0x5f, 0x8c, 0x8b, 0xc7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x6, 0x8, 0x9, 0x2, 0xc, 0x1e, 0x33, 0x41, 0x46, 0xd, 0x31, 0x9a, 0xe3, 0xff, 0x5, 0x24, 0xb4, 0xe2, 0x39, 0xf4, 0x44, 0xa, 0x47, 0x42, 0x45, 0x3d, 0xf8, 0x2a, 0xcd, 0x11, 0x3f, 0xd3, 0xfd, 0x2b, 0xb1, 0x1b, 0xa4, 0x4f, 0x0, 0x0, 0x0, 0x90, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xca, 0xb5, 0x75, 0xc4, 0x50, 0x0, 0x5, 0xd1, 0xf7, 0x49, 0xcc, 0xcc, 0xdc, 0x7f, 0x8b, 0x2b, 0xe6, 0xc8, 0xb1, 0x75, 0xc3, 0x39, 0x3, 0x80, 0x50, 0xc6, 0xc5, 0x84, 0x33, 0x4a, 0x30, 0x91, 0x64, 0x45, 0xd5, 0xf4, 0x89, 0xa6, 0x2a, 0xb2, 0x4, 0x48, 0x86, 0x69, 0xd9, 0xce, 0xc2, 0xb6, 0x4c, 0x43, 0x82, 0xeb, 0xf9, 0x4e, 0xb0, 0x71, 0x7c, 0xcf, 0x5, 0xf, 0xa3, 0xe0, 0x10, 0x85, 0x1c, 0x22, 0x76, 0xce, 0xe0, 0xc4, 0x2, 0x49, 0x7a, 0xd, 0x69, 0x2, 0xa1, 0xff, 0xb3, 0x70, 0xda, 0x42, 0x76, 0xf8, 0x73, 0xf8, 0xc2, 0x17, 0x92, 0xf4, 0x19, 0xf2, 0x6b, 0xc8, 0x13, 0xf0, 0xa2, 0x3c, 0x43, 0x59, 0x70, 0xb8, 0x55, 0x7d, 0x2c, 0x4e, 0x5d, 0xb9, 0x90, 0x9a, 0xb6, 0xeb, 0x9d, 0x45, 0xdf, 0xb5, 0x8d, 0x4, 0xd0, 0x66, 0x68, 0xf5, 0x74, 0xa2, 0xb7, 0x43, 0x43, 0x31, 0x91, 0x98, 0x48, 0x16, 0x82, 0x49, 0x78, 0x1b, 0x1, 0xf, 0xa7, 0x50, 0x68, 0x35, 0xb8, 0x84, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_default_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x39, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0xe, 0xb, 0x10, 0xe, 0xb, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x24, 0x1e, 0x27, 0x16, 0x12, 0x19, 0xff, 0xff, 0xff, 0x2b, 0x4d, 0xfd, 0x66, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x46, 0x47, 0x3f, 0x2b, 0x11, 0x3, 0xfd, 0xd3, 0xcd, 0x2a, 0x73, 0x45, 0xf8, 0x3d, 0x3f, 0x57, 0xda, 0x84, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x12, 0x7b, 0xbc, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x64, 0x2, 0x2, 0x46, 0x8, 0xc9, 0xcc, 0xc2, 0xca, 0xc6, 0xc0, 0x8f, 0x4, 0xd8, 0x39, 0x98, 0x59, 0x19, 0x50, 0x80, 0x0, 0x27, 0x17, 0xaa, 0x0, 0x83, 0x20, 0x37, 0x9a, 0x0, 0x3f, 0xd3, 0xc0, 0x8, 0xf0, 0xa0, 0x9, 0xf0, 0xf2, 0x61, 0x3a, 0x1d, 0xc3, 0x73, 0xe8, 0xde, 0x7, 0x0, 0x89, 0x4d, 0x2, 0xf2, 0x16, 0xd3, 0x74, 0x45, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0xe, 0xb, 0x10, 0xe, 0xb, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x16, 0x12, 0x19, 0x0, 0x0, 0x0, 0x19, 0x15, 0x1c, 0x24, 0x1e, 0x27, 0x16, 0x12, 0x19, 0x76, 0x9, 0xd2, 0x13, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x46, 0x47, 0x3f, 0x2b, 0x11, 0x3, 0xfd, 0xd3, 0xcd, 0x2a, 0x73, 0x45, 0xf8, 0x3d, 0x3f, 0x57, 0xda, 0x84, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x64, 0x2, 0x2, 0x46, 0x8, 0xc9, 0xcc, 0xc2, 0xca, 0xc6, 0xc0, 0x8f, 0x4, 0xd8, 0x39, 0x98, 0x59, 0x19, 0x50, 0x80, 0x0, 0x27, 0x17, 0x3, 0x2a, 0x10, 0xe4, 0x46, 0x13, 0xe0, 0x67, 0x1a, 0x18, 0x1, 0x1e, 0x34, 0x1, 0x5e, 0x3e, 0xc, 0xa7, 0x63, 0x78, 0xe, 0xc3, 0xfb, 0x0, 0x89, 0x4d, 0x2, 0xf2, 0xa2, 0x23, 0x3b, 0xc4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_default_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb7, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x9d, 0x91, 0x3d, 0x6a, 0x42, 0x61, 0x10, 0x45, 0xcf, 0x8c, 0x4f, 0x22, 0x7c, 0x58, 0x84, 0x14, 0x2e, 0xc0, 0xf5, 0x64, 0x17, 0xba, 0x3, 0x2d, 0x4, 0x41, 0x17, 0x96, 0x2a, 0x65, 0x5c, 0x43, 0x7a, 0xb, 0x53, 0xfa, 0xc3, 0x63, 0x9c, 0x6b, 0xf1, 0x4, 0xf9, 0x24, 0x31, 0x21, 0xb7, 0x1b, 0xe6, 0x14, 0x33, 0xe7, 0x1a, 0x80, 0xc, 0xc7, 0x1, 0xa7, 0x4b, 0x2, 0x49, 0x9a, 0xc0, 0x34, 0xc2, 0xbb, 0x11, 0xae, 0x58, 0x92, 0x4, 0x2d, 0x2d, 0x61, 0xb2, 0x99, 0xf8, 0x26, 0xfd, 0xaf, 0xe1, 0xdb, 0x62, 0xca, 0x89, 0x40, 0x88, 0x35, 0x13, 0xb6, 0x15, 0xb0, 0x7d, 0x99, 0x68, 0xfd, 0xae, 0xa2, 0x1e, 0x42, 0xcc, 0x9, 0x4a, 0x5, 0x94, 0x71, 0xd8, 0xfc, 0xa8, 0x67, 0xf5, 0x1d, 0x40, 0x34, 0xec, 0x2b, 0x60, 0xff, 0xd9, 0x48, 0x3, 0x1a, 0xdc, 0x79, 0x14, 0xbf, 0x3d, 0xf6, 0x4f, 0x80, 0xdf, 0x80, 0xfc, 0x2b, 0x60, 0x77, 0x16, 0x3a, 0x13, 0x76, 0x24, 0x48, 0x7, 0x28, 0x2c, 0x89, 0x6a, 0x1d, 0xc3, 0xe5, 0xae, 0x7c, 0xd0, 0x92, 0x3f, 0xa8, 0xb6, 0x53, 0xd9, 0xac, 0x5e, 0x39, 0x10, 0x8f, 0xcb, 0x4a, 0x3b, 0x5b, 0x67, 0x12, 0x80, 0xa7, 0xea, 0xbc, 0x6b, 0xdd, 0x17, 0xbe, 0x3f, 0x4f, 0x23, 0x27, 0x82, 0x63, 0x73, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x8a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x81, 0xff, 0x8c, 0xff, 0x99, 0xff, 0xb3, 0x2, 0x21, 0x3b, 0x4, 0x82, 0xd8, 0x40, 0x11, 0x46, 0x88, 0xa4, 0xf8, 0x7f, 0x49, 0x20, 0x14, 0xff, 0x2f, 0xa, 0x84, 0x8, 0xb6, 0xe0, 0x7f, 0x6e, 0xa0, 0x22, 0x90, 0x92, 0x92, 0xff, 0xd8, 0x60, 0xe5, 0x9b, 0xb6, 0x15, 0xff, 0x79, 0xc1, 0x4a, 0xb0, 0x83, 0x17, 0xc2, 0x29, 0xff, 0x1b, 0xe, 0x1, 0x4d, 0x61, 0xc6, 0xa1, 0x80, 0x5b, 0xf9, 0xf, 0x63, 0xe9, 0x77, 0xa0, 0x45, 0xac, 0xc, 0x38, 0x0, 0xd8, 0x72, 0xa0, 0x5b, 0xd8, 0xf1, 0x2b, 0x10, 0x27, 0xa4, 0x40, 0x92, 0x7c, 0x5, 0x8, 0x2b, 0xc8, 0x77, 0xe4, 0xb, 0xe1, 0xd2, 0x6f, 0x78, 0xbc, 0xf9, 0x87, 0x17, 0x18, 0x50, 0x7, 0x40, 0x1, 0x85, 0x23, 0xa8, 0x4b, 0xbf, 0x3, 0xc3, 0x91, 0x1f, 0x14, 0xd4, 0x78, 0x23, 0xb, 0x2d, 0xa0, 0xff, 0xb3, 0x23, 0x20, 0x22, 0xba, 0x1, 0x39, 0x96, 0x8a, 0xa5, 0x9b, 0x88, 0xa3, 0x56, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_position_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x6, 0xf, 0x3b, 0x3b, 0x49, 0x6e, 0xe4, 0x1e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x90, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0xd7, 0xbd, 0x9, 0xc0, 0x20, 0x10, 0x5, 0xe0, 0x53, 0x2c, 0xdd, 0x40, 0x47, 0x70, 0x7, 0x67, 0x77, 0x7, 0x47, 0x88, 0x1b, 0xd8, 0x9b, 0xe6, 0x84, 0x53, 0x48, 0x10, 0x14, 0x52, 0xe4, 0x5d, 0x25, 0xfe, 0x7c, 0x9e, 0x58, 0x3d, 0xa2, 0xcd, 0x52, 0x7d, 0x50, 0x63, 0xb8, 0x88, 0xc8, 0x2d, 0x9e, 0x2b, 0x36, 0x65, 0x4f, 0xf2, 0x30, 0x3, 0x4b, 0x25, 0xf7, 0x1b, 0x9e, 0x73, 0x36, 0x65, 0xb5, 0xd0, 0x49, 0xb1, 0x29, 0x7b, 0x9b, 0xb2, 0xaf, 0x31, 0x34, 0x9, 0xc8, 0x67, 0x50, 0xc7, 0x9e, 0x6e, 0x96, 0xed, 0xeb, 0x69, 0x8f, 0x1b, 0xde, 0x36, 0x15, 0xaf, 0xd, 0xdd, 0xe9, 0xdd, 0x5f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x1f, 0x1, 0xe5, 0x2d, 0x3f, 0xf2, 0x5a, 0x91, 0x73, 0x66, 0x4e, 0x65, 0x1c, 0xed, 0xda, 0x52, 0x62, 0x3d, 0x91, 0x5c, 0xcf, 0x64, 0xe7, 0x4f, 0xeb, 0x6, 0x80, 0xff, 0x44, 0x93, 0xd4, 0xd9, 0xea, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x2, 0x3, 0x0, 0x0, 0x0, 0x6e, 0x13, 0x1f, 0x5, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf4, 0x3f, 0x2c, 0xf4, 0x3f, 0x2c, 0x1c, 0x3e, 0x10, 0xcd, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xe4, 0xd1, 0xf4, 0xeb, 0x59, 0x0, 0x0, 0x0, 0x30, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x0, 0x3, 0xb6, 0x55, 0xab, 0x26, 0x30, 0x88, 0x30, 0x0, 0x91, 0x42, 0xd6, 0x4a, 0xe, 0x6, 0x45, 0x7, 0x46, 0xf, 0x6, 0x25, 0x6, 0x86, 0xe, 0x20, 0x31, 0x4a, 0x80, 0x42, 0x3, 0x1c, 0x2e, 0xe0, 0x10, 0x82, 0x84, 0x15, 0x1c, 0x0, 0x0, 0x41, 0x2d, 0x2b, 0x21, 0xbb, 0xb7, 0x1a, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_node_selected_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x6, 0x0, 0x0, 0x0, 0x13, 0x7d, 0xf7, 0x96, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x17, 0xd, 0x4, 0x3b, 0xfa, 0x91, 0x2a, 0xb6, 0x0, 0x0, 0x3, 0x44, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xed, 0x97, 0x3f, 0x68, 0xdc, 0x76, 0x14, 0xc7, 0xbf, 0xef, 0xa7, 0x9f, 0x7e, 0x3a, 0xdd, 0x39, 0xf6, 0xdd, 0x95, 0xb3, 0x3, 0xc1, 0x75, 0x1b, 0x70, 0xa, 0xe9, 0x98, 0x25, 0x93, 0x87, 0x52, 0x3a, 0x4, 0x2, 0xce, 0xe0, 0xd2, 0x34, 0x35, 0x94, 0x8e, 0x1d, 0xbc, 0xd5, 0x4b, 0xc7, 0x2e, 0x25, 0x63, 0x2, 0x5d, 0xa, 0xa5, 0xb1, 0x1b, 0x2, 0xf5, 0xd0, 0x40, 0xa0, 0x90, 0x10, 0x3a, 0x64, 0xca, 0x92, 0x31, 0x81, 0x24, 0xd0, 0xd2, 0x9a, 0x40, 0x2f, 0x17, 0xdf, 0x1f, 0xfb, 0x74, 0xf2, 0xe9, 0x27, 0xfd, 0x5e, 0x7, 0x49, 0xb6, 0x4e, 0xe7, 0xea, 0x86, 0x6e, 0xe5, 0x1e, 0xdc, 0x49, 0x42, 0xef, 0x7d, 0xde, 0xf7, 0x7d, 0xf5, 0x13, 0xe8, 0x47, 0xcc, 0x4c, 0x0, 0xc4, 0xbd, 0x7b, 0x4f, 0x9c, 0xb0, 0xdd, 0x71, 0xdb, 0xfb, 0x2d, 0xc7, 0xb0, 0x11, 0x5a, 0x7, 0x84, 0x4c, 0xd8, 0xb6, 0x62, 0x41, 0xc2, 0xd4, 0x67, 0x1b, 0x43, 0x59, 0xaf, 0xf9, 0x97, 0x2f, 0x5f, 0x18, 0x2, 0x30, 0xc4, 0xcc, 0xd6, 0xdd, 0x1f, 0xef, 0x9e, 0xea, 0x79, 0x83, 0x33, 0xed, 0x6e, 0xf7, 0x6c, 0xaf, 0xd7, 0x59, 0xe8, 0x7b, 0xfd, 0x72, 0x10, 0x4, 0x32, 0xb, 0x50, 0x4a, 0x85, 0x33, 0x95, 0x99, 0xc1, 0xdc, 0x5c, 0xad, 0x59, 0xaf, 0x56, 0x7f, 0x9f, 0xab, 0x94, 0x5f, 0xad, 0x7e, 0xbe, 0x7a, 0x40, 0x5b, 0x5b, 0xf7, 0x2b, 0x41, 0xbb, 0xf9, 0x6e, 0xa7, 0xd7, 0x5e, 0xb9, 0x72, 0x75, 0xe5, 0x86, 0x72, 0xa4, 0x85, 0x82, 0x8, 0x86, 0x61, 0xf4, 0xcb, 0x9d, 0x47, 0x1b, 0xb5, 0xb9, 0xfa, 0x23, 0x55, 0x5f, 0xf8, 0x43, 0xea, 0x4e, 0xb7, 0xdc, 0x7c, 0xf3, 0xfa, 0xdc, 0xc7, 0xeb, 0x1f, 0xdc, 0x64, 0x66, 0x71, 0xb8, 0x37, 0xbb, 0x2b, 0x1d, 0xb, 0x44, 0x23, 0x13, 0x80, 0x99, 0x11, 0xe, 0x23, 0x50, 0x65, 0x6f, 0x71, 0xf5, 0x93, 0x95, 0x9b, 0x3f, 0x6f, 0xff, 0xb6, 0x76, 0x9a, 0x9c, 0xa6, 0x8, 0x42, 0x5f, 0x79, 0xfd, 0x83, 0x79, 0xa7, 0x24, 0x5, 0xfc, 0xfa, 0x2e, 0x9, 0x42, 0xa8, 0xd, 0xc2, 0x20, 0x1a, 0xfd, 0x69, 0x3, 0x12, 0x4, 0xf8, 0xf5, 0x5d, 0xa7, 0x24, 0x85, 0xd7, 0x3f, 0x98, 0xf, 0x42, 0x5f, 0x9, 0xc3, 0x46, 0xc, 0xfc, 0x81, 0xb, 0x0, 0x91, 0x66, 0x30, 0x1b, 0x10, 0x0, 0x98, 0x6c, 0x7b, 0x80, 0xc0, 0x60, 0x66, 0x44, 0x21, 0x3, 0x0, 0x6, 0xfe, 0xc0, 0x35, 0x6c, 0x84, 0xd0, 0x5a, 0x53, 0x84, 0x88, 0x0, 0x80, 0x13, 0xd9, 0xcc, 0xc, 0x88, 0xb8, 0x10, 0x0, 0x40, 0x0, 0x1b, 0x0, 0xcc, 0x0, 0xc7, 0x39, 0x11, 0x22, 0xd2, 0x5a, 0x93, 0xb4, 0x6d, 0x9b, 0x11, 0x25, 0x89, 0x86, 0xc1, 0x20, 0x80, 0x18, 0xa0, 0xe3, 0xee, 0x47, 0xd0, 0xcc, 0x31, 0xad, 0x91, 0x79, 0xa3, 0x40, 0x4, 0x80, 0x91, 0xe6, 0xe5, 0x83, 0x73, 0x37, 0x64, 0xee, 0x2e, 0xd8, 0x24, 0x9, 0xc4, 0xc7, 0xa, 0xb2, 0x6a, 0x8a, 0x0, 0x1c, 0xf7, 0xce, 0x5e, 0xc4, 0xc5, 0xe6, 0x18, 0x92, 0x57, 0x36, 0x2, 0x30, 0x26, 0x33, 0x7b, 0xe2, 0x1e, 0x71, 0xe2, 0xb, 0x33, 0x68, 0xf2, 0x8, 0xd9, 0x16, 0x94, 0xd1, 0x13, 0xff, 0x9b, 0x49, 0xa, 0xc0, 0x6, 0x6c, 0x72, 0xf6, 0x8f, 0xbb, 0x58, 0xe0, 0x41, 0x32, 0x77, 0x22, 0x1a, 0xc9, 0xf2, 0x49, 0x87, 0x89, 0xcf, 0x8a, 0x14, 0xc4, 0x0, 0x93, 0x14, 0x66, 0xba, 0xd1, 0xf1, 0xec, 0xa6, 0x18, 0x60, 0xe2, 0xfa, 0x91, 0xde, 0xd9, 0xae, 0x34, 0xf9, 0x31, 0x52, 0xba, 0x1e, 0x28, 0x5d, 0x4c, 0x94, 0xfa, 0x99, 0xbc, 0xf, 0x45, 0xa, 0x4c, 0x5c, 0x38, 0xd6, 0xc9, 0xe0, 0xe8, 0x89, 0xe4, 0xad, 0x1d, 0x5f, 0xca, 0x9c, 0x7f, 0x15, 0x8b, 0x63, 0xdc, 0xc4, 0x7c, 0x8f, 0x8c, 0x91, 0xb9, 0x93, 0x71, 0xc0, 0xd7, 0xdf, 0x7c, 0xf5, 0xea, 0xd9, 0x8b, 0xa7, 0x85, 0x1d, 0xcf, 0x9f, 0x7b, 0x1f, 0xdf, 0xdf, 0xfa, 0x76, 0xf1, 0x44, 0xc0, 0xd9, 0xa5, 0x65, 0x58, 0xc2, 0x2e, 0x4, 0x2c, 0x2d, 0xbe, 0xf3, 0xef, 0xa, 0x3c, 0xaf, 0x8f, 0xde, 0x7e, 0xb7, 0x10, 0xe0, 0x79, 0xfd, 0x91, 0x6b, 0x81, 0xff, 0x18, 0x53, 0xc0, 0x14, 0x30, 0x5, 0x4c, 0x1, 0x53, 0xc0, 0x14, 0x30, 0x5, 0xfc, 0xff, 0x0, 0x5a, 0x6b, 0x82, 0x75, 0xe2, 0xe7, 0xcf, 0xc9, 0x91, 0xe6, 0x58, 0x19, 0x5, 0x16, 0x2c, 0x6, 0x0, 0x5b, 0xca, 0x89, 0xf5, 0x69, 0x4e, 0x5a, 0x23, 0x1c, 0xe5, 0x44, 0x8e, 0x52, 0x1, 0x0, 0x94, 0xdd, 0x99, 0x89, 0x80, 0x34, 0xc7, 0x51, 0x2a, 0x70, 0x94, 0x13, 0x49, 0x25, 0xdd, 0xa0, 0xe4, 0x96, 0x5b, 0xc3, 0x43, 0xcd, 0x1b, 0x9b, 0x9f, 0x5e, 0xbc, 0x71, 0x9d, 0x1e, 0xf, 0xfc, 0x3, 0xe8, 0x30, 0x1c, 0xd9, 0x74, 0xd9, 0x52, 0xa2, 0xec, 0x9e, 0xc2, 0xc6, 0xe6, 0xd5, 0x8b, 0xc3, 0x43, 0xcd, 0x25, 0xb7, 0xdc, 0x52, 0xd2, 0xd, 0x68, 0x6b, 0xeb, 0x7e, 0x65, 0xef, 0xaf, 0x97, 0xcb, 0xdd, 0xfd, 0xce, 0x87, 0x9f, 0x7d, 0x71, 0xe9, 0xba, 0xe3, 0xda, 0x85, 0x4e, 0xc, 0x7d, 0xcd, 0x3f, 0xfd, 0xf0, 0xeb, 0x66, 0x75, 0xb6, 0xf6, 0xf0, 0xad, 0xb7, 0x97, 0x5f, 0x12, 0x33, 0x5b, 0xb7, 0xbf, 0xbb, 0x3d, 0xdb, 0xea, 0x74, 0x97, 0x3a, 0xdd, 0xee, 0x7b, 0x3, 0xdf, 0x9b, 0xd7, 0x5a, 0xdb, 0xc6, 0x8c, 0x7e, 0xad, 0xa, 0x21, 0x60, 0xdb, 0xb6, 0x2e, 0xbb, 0x95, 0xd7, 0xb5, 0x6a, 0xf5, 0x79, 0xa3, 0x56, 0xfd, 0xf3, 0xda, 0x97, 0xd7, 0xf6, 0x29, 0xdd, 0xbd, 0x6f, 0x6f, 0x3f, 0x28, 0xf5, 0xff, 0x6e, 0x56, 0xb4, 0x19, 0x2a, 0x66, 0x73, 0xe2, 0xe3, 0x25, 0x12, 0xc6, 0x16, 0x4e, 0x30, 0x73, 0x7a, 0xc1, 0x5b, 0x5f, 0xff, 0xe8, 0x10, 0xc0, 0xd1, 0xf6, 0x4, 0xcc, 0x4c, 0x3b, 0x3b, 0x3b, 0xa2, 0xd1, 0x68, 0x14, 0x8e, 0xd0, 0x6a, 0xb5, 0x78, 0x6d, 0x6d, 0xcd, 0x10, 0xc5, 0xdb, 0xba, 0x7f, 0x0, 0xb2, 0x1f, 0xaf, 0x82, 0x62, 0x7a, 0x69, 0xbb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x40, 0x8, 0x3, 0x0, 0x0, 0x0, 0x24, 0xa3, 0x7, 0xa4, 0x0, 0x0, 0x1, 0x5f, 0x50, 0x4c, 0x54, 0x45, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb2, 0xb2, 0xcc, 0xae, 0xa0, 0xbb, 0x9c, 0x92, 0xa6, 0x9a, 0x91, 0xa4, 0x95, 0x8c, 0x9e, 0xaf, 0x9f, 0xaf, 0xa0, 0x94, 0xa5, 0x8e, 0x84, 0x95, 0x7f, 0x75, 0x84, 0x73, 0x6a, 0x78, 0x6d, 0x64, 0x72, 0xa2, 0xa2, 0xb9, 0x9c, 0x90, 0xa2, 0x8b, 0x81, 0x90, 0xdc, 0xda, 0xce, 0xe2, 0xe1, 0xd2, 0x9d, 0x91, 0xa9, 0x85, 0x7c, 0x8c, 0xdb, 0xd9, 0xce, 0xdb, 0xd9, 0xcd, 0xda, 0xce, 0xe0, 0xde, 0xd5, 0xe3, 0xdf, 0xd6, 0xe4, 0x97, 0x8d, 0xa0, 0x7a, 0x70, 0x7f, 0xdb, 0xd0, 0xdf, 0xdb, 0xd0, 0xe1, 0xda, 0xd0, 0xe1, 0x70, 0x67, 0x75, 0xd8, 0xcb, 0xde, 0xda, 0xcf, 0xdf, 0xdb, 0xce, 0xe1, 0xdb, 0xcf, 0xe1, 0xdb, 0xd0, 0xe0, 0xda, 0xcf, 0xe0, 0xd8, 0xcc, 0xde, 0x90, 0x87, 0x99, 0x6d, 0x67, 0x72, 0xd7, 0xcc, 0xdf, 0xda, 0xce, 0xdf, 0xd8, 0xcb, 0xdf, 0xd7, 0xca, 0xde, 0xd9, 0xcc, 0xdf, 0xd9, 0xcd, 0xdf, 0xd6, 0xc9, 0xdd, 0xd9, 0xcd, 0xde, 0xd6, 0xc8, 0xdc, 0xd5, 0xc8, 0xdc, 0xd7, 0xcb, 0xdd, 0xd7, 0xca, 0xdd, 0xd5, 0xc7, 0xdc, 0xd3, 0xc6, 0xdb, 0xd5, 0xc9, 0xdc, 0xd5, 0xc9, 0xdd, 0xd6, 0xc9, 0xdc, 0xd4, 0xc6, 0xdb, 0xd3, 0xc5, 0xdb, 0xd5, 0xc8, 0xdb, 0xd4, 0xc8, 0xdc, 0xd3, 0xc4, 0xd9, 0xd4, 0xc6, 0xda, 0xd2, 0xc3, 0xd9, 0xd3, 0xc5, 0xda, 0xd2, 0xc5, 0xd9, 0xd3, 0xc5, 0xd9, 0xd2, 0xc5, 0xda, 0xd1, 0xc2, 0xd9, 0xd2, 0xc4, 0xd8, 0xd2, 0xc4, 0xd9, 0xd0, 0xc2, 0xd9, 0xd0, 0xc1, 0xd7, 0xd0, 0xc2, 0xd7, 0xd0, 0xc2, 0xd8, 0xd1, 0xc2, 0xd7, 0xcf, 0xc1, 0xd7, 0xd0, 0xc2, 0xd6, 0xcf, 0xc1, 0xd6, 0xcf, 0xc2, 0xd7, 0xcf, 0xc0, 0xd7, 0xce, 0xbf, 0xd6, 0xce, 0xc0, 0xd5, 0xce, 0xc0, 0xd6, 0xce, 0xbf, 0xd5, 0xcd, 0xbf, 0xd5, 0xcd, 0xbe, 0xd5, 0xcd, 0xbe, 0xd4, 0xcc, 0xbd, 0xd5, 0xcc, 0xbd, 0xd4, 0xcc, 0xbc, 0xd4, 0x47, 0x40, 0x4a, 0x1d, 0x1a, 0x1f, 0x69, 0x5f, 0x6f, 0x4a, 0x42, 0x4f, 0x5e, 0x54, 0x63, 0x3b, 0x34, 0x3f, 0x5e, 0x55, 0x63, 0x63, 0x59, 0x67, 0x77, 0x6d, 0x7b, 0x6d, 0x62, 0x73, 0x7f, 0x76, 0x85, 0xdb, 0xd9, 0xcd, 0xdb, 0xd8, 0xcd, 0x6d, 0x62, 0x74, 0x8f, 0x84, 0x94, 0x7f, 0x76, 0x83, 0xdb, 0xd8, 0xcd, 0xa4, 0x95, 0xa4, 0x7e, 0x74, 0x84, 0x74, 0x6b, 0x79, 0x6f, 0x66, 0x74, 0x96, 0x8a, 0xa2, 0x91, 0x88, 0x9b, 0x0, 0x0, 0x0, 0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xbf, 0xf0, 0xc9, 0xec, 0x71, 0x0, 0x0, 0x0, 0x75, 0x74, 0x52, 0x4e, 0x53, 0x1, 0x3, 0xa, 0x13, 0x1a, 0x1c, 0x1d, 0x10, 0x2b, 0x4d, 0x64, 0x6e, 0x72, 0xb, 0x2c, 0x6a, 0xfc, 0xff, 0x15, 0x52, 0xfd, 0xff, 0xe2, 0xe2, 0xe2, 0x1b, 0x68, 0xe2, 0xe2, 0xe2, 0x71, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0x1e, 0x72, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xe2, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0x6b, 0xc7, 0x56, 0xfe, 0xff, 0xc7, 0x30, 0x74, 0xfe, 0x11, 0x57, 0x6d, 0x72, 0x16, 0x1c, 0x0, 0x3, 0x4, 0x35, 0xf5, 0x4, 0x26, 0x0, 0x0, 0x1, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0xd0, 0x35, 0x82, 0x1c, 0x31, 0x14, 0x84, 0xe1, 0xbf, 0xa4, 0xd7, 0x32, 0x33, 0xb3, 0xf, 0x63, 0x8e, 0xcd, 0x10, 0xcd, 0x99, 0x1c, 0x3a, 0x75, 0xe8, 0xcc, 0xbe, 0x8e, 0x99, 0x79, 0xb9, 0x49, 0x6f, 0x49, 0xd3, 0xcb, 0x7b, 0x82, 0xa9, 0xac, 0x3e, 0xb1, 0xc, 0xad, 0x4, 0xf0, 0x95, 0x98, 0xd2, 0x6, 0x68, 0xec, 0x60, 0xa9, 0xac, 0x52, 0xb2, 0x6a, 0xf3, 0x92, 0x3d, 0x9a, 0xdf, 0x2f, 0x39, 0x20, 0xf7, 0xb9, 0x7d, 0x6e, 0xbf, 0xcf, 0x62, 0xea, 0xaa, 0x96, 0x24, 0x69, 0xce, 0xbe, 0xd9, 0x55, 0x4d, 0xef, 0x5b, 0xd8, 0xbb, 0x90, 0x9a, 0xa6, 0x39, 0x21, 0xf6, 0x5d, 0xb5, 0x77, 0xa9, 0x8a, 0x7, 0x35, 0xd5, 0xc0, 0x19, 0x32, 0x9f, 0xcf, 0x1b, 0x10, 0x3d, 0x9c, 0x1, 0x20, 0x2, 0x6, 0x84, 0xbf, 0x24, 0x9a, 0x44, 0x73, 0xac, 0x80, 0x4e, 0x80, 0x5c, 0x4e, 0x28, 0x60, 0x2, 0xc9, 0x3d, 0xa8, 0x40, 0x25, 0xe6, 0x0, 0xe, 0xe4, 0x2, 0x51, 0x1c, 0x2, 0x40, 0x5, 0x82, 0xa4, 0x2c, 0x3c, 0x76, 0xc3, 0x12, 0x51, 0xfb, 0x9e, 0xba, 0xdb, 0x3b, 0x6c, 0x2a, 0x45, 0xd8, 0xaf, 0x3c, 0x86, 0x3e, 0x57, 0x31, 0xc7, 0x7e, 0x98, 0x51, 0x25, 0x39, 0xca, 0x15, 0x1a, 0x3, 0x2, 0x8f, 0xc0, 0x70, 0xa, 0x20, 0x1c, 0x2f, 0x10, 0x87, 0x2f, 0x1c, 0x66, 0xec, 0xe, 0x1b, 0x33, 0x81, 0xd, 0x99, 0xc0, 0x55, 0xfd, 0x8, 0x5e, 0x4a, 0xe0, 0x82, 0x1b, 0xf3, 0x68, 0xc, 0x62, 0x7e, 0xaf, 0x4d, 0xdf, 0x79, 0x15, 0xf2, 0x30, 0xe3, 0xfa, 0x1b, 0xab, 0xc3, 0x3d, 0x59, 0xe3, 0x99, 0xa0, 0xe4, 0xf7, 0xbc, 0xb6, 0xd6, 0xa4, 0x97, 0x65, 0xc6, 0x63, 0xf7, 0xd6, 0x66, 0x62, 0x1f, 0x9f, 0xe9, 0x5, 0x30, 0x72, 0xef, 0xe2, 0x8c, 0xf9, 0xf3, 0x83, 0x23, 0xbd, 0x3e, 0xf, 0x2c, 0x6e, 0xbb, 0xf7, 0xff, 0x5, 0x5f, 0xfe, 0xb3, 0x14, 0x31, 0xf4, 0x31, 0x33, 0xfa, 0x41, 0xd3, 0xe9, 0xe7, 0x22, 0x6, 0x0, 0xb4, 0xb3, 0x74, 0xef, 0x4f, 0xde, 0x59, 0x95, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char graph_port_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x6, 0x0, 0x0, 0x0, 0x8d, 0x32, 0xcf, 0xbd, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xc6, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x6d, 0x90, 0x3d, 0x4e, 0xc4, 0x30, 0x14, 0x84, 0xbf, 0xb1, 0xa8, 0x92, 0x48, 0x39, 0x46, 0xe2, 0x9a, 0x9f, 0x12, 0xc1, 0xbd, 0x16, 0x25, 0x4b, 0x41, 0xb, 0x67, 0xa1, 0xa7, 0xa2, 0x63, 0xa1, 0x76, 0x94, 0x5b, 0x58, 0x72, 0x52, 0x3e, 0xd3, 0xc4, 0x11, 0xda, 0xe5, 0xab, 0x46, 0xa3, 0xd1, 0x68, 0xde, 0x13, 0x1b, 0x21, 0x84, 0x7, 0x49, 0x3, 0x70, 0xbb, 0x59, 0x5f, 0xc0, 0x5b, 0xdf, 0xf7, 0xef, 0x0, 0x2, 0x98, 0xa6, 0xe9, 0x0, 0x1c, 0x1, 0xc7, 0x19, 0x39, 0xe7, 0x67, 0xef, 0xfd, 0xa0, 0xad, 0xe9, 0x3, 0x70, 0x6d, 0xdb, 0x52, 0xd7, 0x35, 0x0, 0xcb, 0xb2, 0x10, 0x63, 0x4, 0x30, 0xe7, 0xdc, 0xe3, 0x95, 0xa4, 0xb1, 0x84, 0x9a, 0xa6, 0xd9, 0x9b, 0x8a, 0x8e, 0x31, 0x3a, 0x33, 0x1b, 0x1d, 0x70, 0xd, 0xec, 0x4d, 0x7f, 0xa9, 0xaa, 0xaa, 0xc8, 0x1b, 0x7, 0xe4, 0x8b, 0xc4, 0x25, 0xd9, 0x1, 0x3f, 0x65, 0xd3, 0x39, 0xeb, 0xba, 0x16, 0xf9, 0xed, 0x80, 0xd7, 0x6d, 0xb, 0x29, 0x25, 0xcc, 0xc, 0x33, 0x23, 0xa5, 0xb4, 0x1f, 0x23, 0x69, 0x14, 0x40, 0x8, 0xe1, 0x28, 0xe9, 0xf0, 0xcf, 0x7b, 0x2c, 0xe7, 0xfc, 0xe4, 0xbd, 0x7f, 0x51, 0x71, 0xe6, 0x79, 0xbe, 0x37, 0xb3, 0x1, 0xb8, 0xdb, 0x76, 0x9f, 0x24, 0x8d, 0x5d, 0xd7, 0x7d, 0x2, 0xfc, 0x2, 0xfb, 0x83, 0x50, 0x87, 0x89, 0x31, 0xee, 0x78, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xce, 0x41, 0xa, 0x83, 0x30, 0x10, 0x85, 0xe1, 0xb9, 0x98, 0xe2, 0x9, 0x3c, 0x50, 0xe9, 0xc6, 0x83, 0x45, 0x7b, 0x8b, 0xfc, 0x7a, 0x1, 0xd7, 0x49, 0xba, 0xd, 0xd3, 0x79, 0xd0, 0x16, 0x41, 0xfe, 0x6c, 0xe6, 0x83, 0xc0, 0x33, 0x8f, 0xf2, 0xc4, 0xc6, 0x3b, 0x5a, 0x99, 0x75, 0xc7, 0xe3, 0x49, 0xc7, 0x7f, 0xe5, 0x25, 0x30, 0x4f, 0xa2, 0xd3, 0x6b, 0x74, 0x8a, 0xfb, 0x31, 0x1a, 0x2f, 0x51, 0xfb, 0x26, 0x66, 0x35, 0x1a, 0x5e, 0xff, 0x58, 0x84, 0xd5, 0xa8, 0x37, 0x2c, 0xc6, 0x76, 0xfb, 0x9e, 0x8c, 0x19, 0x17, 0x97, 0x48, 0x44, 0xdf, 0x7, 0xad, 0x5c, 0x2e, 0x93, 0x7a, 0x7e, 0x68, 0x67, 0x74, 0x8c, 0x24, 0x1a, 0x95, 0xb4, 0xf, 0xba, 0x3f, 0x56, 0x94, 0xa6, 0x72, 0xc9, 0xf9, 0xda, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hseparator_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x3, 0x11, 0xc, 0x4c, 0xf2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x64, 0x60, 0x60, 0xc2, 0x40, 0x8c, 0xc, 0x0, 0x0, 0xc7, 0x0, 0xf, 0xf5, 0x92, 0x2f, 0xa7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x64, 0x60, 0x60, 0xc2, 0x40, 0x8c, 0xc, 0x0, 0x0, 0xc7, 0x0, 0xf, 0xf5, 0x92, 0x2f, 0xa7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hslider_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x4e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xff, 0xff, 0xff, 0x5f, 0xd6, 0x94, 0x4d, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x68, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x1a, 0x96, 0x95, 0x6b, 0xe2, 0xd5, 0x49, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x19, 0xec, 0x6e, 0xb5, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x85, 0xce, 0xdd, 0xe, 0x80, 0x20, 0x8, 0x5, 0x60, 0x54, 0xb4, 0x22, 0xb5, 0x34, 0x7f, 0x7a, 0xff, 0x27, 0x8d, 0xad, 0xd6, 0x6a, 0x5c, 0xf8, 0xdd, 0xc1, 0x6, 0xe7, 0x0, 0x8c, 0xa9, 0x1f, 0x9e, 0xb5, 0x41, 0xeb, 0x26, 0xe6, 0x2c, 0x1a, 0xad, 0x40, 0xcf, 0xb, 0xad, 0xf9, 0x60, 0x79, 0xa5, 0x65, 0xd6, 0x60, 0x7c, 0x28, 0xb5, 0x75, 0xd6, 0x6a, 0x9, 0xde, 0x0, 0x52, 0xe9, 0xe7, 0xa3, 0x17, 0x42, 0xb0, 0xb1, 0x9e, 0xaf, 0x1a, 0xad, 0x5c, 0x88, 0x93, 0x6d, 0xff, 0x3e, 0xdd, 0x37, 0x8e, 0x4d, 0x14, 0xef, 0xd8, 0x48, 0x89, 0x63, 0x45, 0x31, 0x51, 0x7d, 0xe8, 0x2, 0xf5, 0xf, 0x9, 0x67, 0xd9, 0x88, 0x8f, 0x5b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x57, 0x2e, 0xcb, 0x70, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x68, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x1a, 0x96, 0x95, 0x6b, 0xe2, 0xd5, 0x49, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x4f, 0x83, 0x11, 0x3, 0x1, 0x10, 0xcc, 0x39, 0xef, 0xfe, 0xb, 0x7d, 0xdb, 0xc6, 0x8e, 0x8e, 0xb, 0xf8, 0x9d, 0x70, 0x1d, 0x9c, 0x46, 0x2d, 0xcc, 0x18, 0xea, 0x11, 0x80, 0xda, 0xb7, 0x36, 0xe, 0xf2, 0xbe, 0x2f, 0x80, 0x1c, 0xb0, 0xe5, 0xa2, 0x1f, 0xa5, 0xc0, 0xea, 0x12, 0x2c, 0x4, 0x75, 0x52, 0x80, 0x38, 0x46, 0x2b, 0x65, 0x9d, 0xa7, 0x97, 0xc1, 0xf5, 0x25, 0x82, 0x7a, 0x47, 0x4a, 0x83, 0xac, 0x93, 0x33, 0x8f, 0x83, 0xaa, 0xb2, 0xb4, 0xb8, 0x18, 0xbb, 0x58, 0xff, 0x4e, 0xdb, 0x1, 0xc3, 0xf1, 0x34, 0x3b, 0x7e, 0xbc, 0xb3, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hslider_grabber_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x85, 0xd1, 0x3f, 0x4b, 0xc3, 0x40, 0x18, 0xc7, 0xf1, 0xef, 0x25, 0xad, 0x89, 0xa9, 0x70, 0x83, 0x43, 0x5d, 0xc4, 0x21, 0x6e, 0x4a, 0x7, 0x47, 0xdf, 0x83, 0x53, 0x16, 0x17, 0xd7, 0x4e, 0xbe, 0x2, 0x5f, 0x85, 0x83, 0xa0, 0xb8, 0x38, 0xb8, 0x88, 0xd0, 0x51, 0x5d, 0x1c, 0x1c, 0x1c, 0x1c, 0x2a, 0xa2, 0xe8, 0x22, 0x2d, 0x82, 0x2d, 0x88, 0x54, 0xed, 0x3f, 0x1b, 0x9a, 0x78, 0x49, 0x1c, 0x9a, 0x54, 0x4f, 0x5, 0x6f, 0x3a, 0xee, 0xf9, 0xf0, 0x3c, 0x3f, 0x9e, 0x83, 0x7f, 0x8e, 0x18, 0xdf, 0x4c, 0x1c, 0x24, 0x5, 0x60, 0x40, 0x17, 0x9f, 0x48, 0x7, 0x26, 0xd3, 0xe5, 0x55, 0xd7, 0x93, 0x25, 0xe8, 0xde, 0xd4, 0x2b, 0xbb, 0x7, 0xbc, 0x8e, 0x88, 0x99, 0x82, 0xa9, 0xf2, 0xda, 0xe2, 0x86, 0x58, 0x78, 0xb7, 0x87, 0xf6, 0xc4, 0xdc, 0xcc, 0xd2, 0x6c, 0xfb, 0xf2, 0x8e, 0x10, 0xc0, 0x48, 0x81, 0x74, 0x3d, 0x55, 0xf4, 0x51, 0x28, 0x7c, 0x54, 0xd1, 0xf5, 0x90, 0xa3, 0x42, 0x6, 0xa, 0xb2, 0x14, 0x90, 0x0, 0x90, 0x10, 0x20, 0x4b, 0x14, 0x74, 0x20, 0x62, 0xf1, 0x3d, 0x7b, 0x24, 0xb2, 0x74, 0x19, 0x8, 0x83, 0x96, 0x39, 0x2e, 0xb, 0x82, 0x37, 0x94, 0xe, 0x6, 0xbd, 0xdb, 0xfc, 0x18, 0xe4, 0x49, 0x9e, 0xf0, 0x75, 0xd0, 0xbf, 0x3e, 0xb6, 0x22, 0x23, 0x7d, 0x9a, 0x4c, 0xce, 0xf6, 0xe8, 0xe9, 0x20, 0xb8, 0xaa, 0x6, 0xcd, 0x1c, 0x0, 0x39, 0x3e, 0x1e, 0x4f, 0xce, 0x7f, 0x76, 0x88, 0x1f, 0x1a, 0xcf, 0xa7, 0xe, 0x6, 0x6, 0xe, 0x8d, 0x23, 0xd5, 0x22, 0xd6, 0x41, 0x42, 0x77, 0x6b, 0x33, 0xaa, 0x59, 0x58, 0xc4, 0xf5, 0x9d, 0xed, 0x6c, 0xc0, 0xd7, 0x26, 0x21, 0xe, 0x7, 0x9d, 0xda, 0xf2, 0x8a, 0x1d, 0x1f, 0xae, 0xdf, 0x57, 0x19, 0xfe, 0x6, 0xa0, 0x9a, 0x2f, 0xf3, 0xed, 0xfe, 0xc5, 0x7e, 0x85, 0xce, 0x5f, 0xbf, 0x39, 0xca, 0x67, 0x21, 0x18, 0x66, 0x3b, 0x0, 0xf8, 0x4, 0x7e, 0x5c, 0x62, 0x33, 0x51, 0xf0, 0xbb, 0xff, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xf3, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x1e, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x96, 0x96, 0xd7, 0x79, 0x70, 0xc6, 0xfb, 0x19, 0xef, 0x3b, 0xf, 0xa6, 0xe5, 0x31, 0x88, 0xa1, 0x2b, 0xe1, 0x4d, 0xcb, 0x9b, 0xf4, 0xa2, 0xef, 0x7f, 0x3b, 0x10, 0xf6, 0xfd, 0x9f, 0xf4, 0x2, 0xa8, 0x84, 0x17, 0x55, 0x81, 0x4c, 0xe7, 0xc1, 0xbe, 0xff, 0x2d, 0xff, 0x9b, 0x81, 0xb0, 0x5, 0xa8, 0xa4, 0xf3, 0x20, 0xd0, 0x22, 0x14, 0xa0, 0x3e, 0xe3, 0x7d, 0x3b, 0x50, 0x12, 0xc, 0x81, 0xa6, 0xcc, 0x78, 0xf, 0x74, 0xb, 0xa, 0xd0, 0x98, 0xf6, 0x1, 0x59, 0xc1, 0xd4, 0xf, 0xc, 0x1a, 0xa8, 0xa, 0x94, 0xfa, 0x6f, 0x77, 0xc1, 0x15, 0x74, 0xfc, 0xef, 0xbb, 0xc7, 0xa0, 0x82, 0xaa, 0x40, 0xbc, 0x71, 0x7d, 0x3f, 0x5c, 0x41, 0xef, 0xff, 0xde, 0xa3, 0xc, 0x52, 0xa8, 0xa, 0xb8, 0x82, 0x52, 0xa7, 0xfd, 0x69, 0x5, 0x4b, 0xb7, 0xfe, 0x9f, 0xf6, 0xcf, 0x37, 0x85, 0x81, 0x7, 0x2d, 0x1c, 0x14, 0xd, 0xfb, 0x1f, 0x74, 0x82, 0x15, 0x74, 0xfe, 0x9f, 0xf8, 0x80, 0x45, 0x83, 0x81, 0x9, 0x55, 0x1, 0x23, 0x83, 0x48, 0xc5, 0x9c, 0xc9, 0xff, 0x5b, 0x81, 0x70, 0xf2, 0xff, 0x92, 0xa9, 0xc, 0xc2, 0x98, 0x41, 0xcd, 0xca, 0xa3, 0x33, 0xe1, 0x76, 0xcf, 0xff, 0x9e, 0xff, 0x13, 0xef, 0xf0, 0xe8, 0x30, 0xb0, 0x62, 0x8b, 0xd, 0x6e, 0xb, 0xff, 0x39, 0x5f, 0xe6, 0x7c, 0x77, 0x8, 0x45, 0xd8, 0x8f, 0x61, 0x4d, 0x51, 0x71, 0x55, 0x2d, 0x83, 0x18, 0x90, 0x85, 0x3, 0xb0, 0x30, 0x70, 0x3, 0x75, 0xb3, 0x20, 0xb, 0x1, 0x0, 0x86, 0xe, 0x79, 0x54, 0x16, 0xbe, 0x69, 0xf5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hslider_grabber_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x7, 0xa, 0x13, 0x2f, 0x7, 0x5e, 0x49, 0xee, 0x14, 0x0, 0x0, 0x0, 0x1d, 0x69, 0x54, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x64, 0x2e, 0x65, 0x7, 0x0, 0x0, 0x0, 0xea, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x20, 0x1a, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x66, 0x9c, 0xe7, 0x7a, 0xd0, 0xe7, 0xbd, 0xcf, 0x7b, 0xd7, 0x83, 0xc6, 0x79, 0xc, 0x62, 0xe8, 0x4a, 0x78, 0x8d, 0xf3, 0x3c, 0x5f, 0xb8, 0xff, 0x77, 0x1, 0x42, 0xf7, 0xff, 0x9e, 0x2f, 0x80, 0x4a, 0x78, 0x51, 0x15, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x85, 0xee, 0xff, 0x5d, 0xf, 0x2, 0x2d, 0x42, 0x1, 0xea, 0x3e, 0xef, 0x5d, 0xe0, 0xa, 0x5c, 0xfe, 0xfb, 0xbc, 0x7, 0xba, 0x5, 0x5, 0x68, 0x78, 0x7f, 0x40, 0x56, 0xe0, 0xfd, 0x81, 0x41, 0x3, 0x55, 0x81, 0x92, 0xc7, 0x6d, 0x57, 0x24, 0x5, 0xee, 0xf7, 0x18, 0x54, 0x50, 0x15, 0x88, 0x3b, 0xae, 0xf7, 0x40, 0x72, 0x83, 0xfb, 0x51, 0x6, 0x29, 0x54, 0x5, 0x5c, 0x9a, 0xa9, 0xde, 0x7f, 0x9c, 0xc1, 0xd2, 0xce, 0xff, 0xbd, 0xff, 0xa9, 0xa7, 0x30, 0xf0, 0xa0, 0x85, 0x83, 0xa0, 0xa1, 0xc7, 0x3, 0x88, 0x25, 0xae, 0xff, 0x3d, 0x1f, 0x30, 0x69, 0x30, 0x30, 0xa1, 0x2a, 0x60, 0x64, 0x10, 0xb1, 0x99, 0xe3, 0x5, 0xd4, 0xed, 0xfc, 0xdf, 0xeb, 0xbf, 0xd5, 0x54, 0x6, 0x61, 0xcc, 0xa0, 0x66, 0x65, 0xd3, 0xf1, 0xb8, 0xed, 0xf6, 0xdf, 0xed, 0xbf, 0xe7, 0x1d, 0x36, 0x1d, 0x6, 0x56, 0x6c, 0xb1, 0xc1, 0x2d, 0xe3, 0xef, 0xf7, 0xc5, 0xef, 0xbb, 0x42, 0x28, 0xba, 0xfd, 0x48, 0xd6, 0x58, 0x16, 0xdb, 0xd6, 0x2, 0xe3, 0x81, 0x11, 0x57, 0x8c, 0xb2, 0x30, 0x70, 0x3, 0x75, 0xb3, 0x20, 0xb, 0x1, 0x0, 0x4, 0x5c, 0x63, 0x9b, 0x17, 0x86, 0x76, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xe7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x1e, 0x30, 0x33, 0xf0, 0x32, 0xc8, 0x30, 0xa8, 0x3, 0xa1, 0xc, 0x90, 0xc5, 0x8c, 0x29, 0x2d, 0x66, 0x9c, 0xe7, 0x7a, 0xd0, 0xe7, 0xbd, 0xcf, 0x7b, 0xd7, 0x83, 0xc6, 0x79, 0xc, 0x62, 0xe8, 0x4a, 0x78, 0x8d, 0xf3, 0x3c, 0x5f, 0xb8, 0xff, 0x77, 0x1, 0x42, 0xf7, 0xff, 0x9e, 0x2f, 0x80, 0x4a, 0x78, 0x51, 0x15, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x81, 0x40, 0x25, 0xae, 0x7, 0x81, 0x16, 0xa1, 0x0, 0x75, 0x9f, 0xf7, 0x2e, 0x30, 0x5, 0x40, 0x53, 0x7c, 0xde, 0x3, 0xdd, 0x82, 0x2, 0x34, 0xbc, 0x3f, 0x20, 0x2b, 0xf0, 0xfe, 0xc0, 0xa0, 0x81, 0xaa, 0x40, 0xc9, 0xe3, 0xb6, 0x2b, 0x92, 0x2, 0xf7, 0x7b, 0xc, 0x2a, 0xa8, 0xa, 0xc4, 0x1d, 0xd7, 0x7b, 0x20, 0xb9, 0xc1, 0xfd, 0x28, 0x83, 0x14, 0xaa, 0x2, 0x2e, 0xcd, 0x54, 0xef, 0x3f, 0xce, 0x60, 0x69, 0xe7, 0xff, 0xde, 0xff, 0xd4, 0x53, 0x18, 0x78, 0xd0, 0xc2, 0x41, 0xd0, 0xd0, 0xe3, 0x1, 0xc4, 0x12, 0xd7, 0xff, 0x9e, 0xf, 0x98, 0x34, 0x18, 0x98, 0x50, 0x15, 0x30, 0x32, 0x88, 0xd8, 0xcc, 0xf1, 0xfa, 0xef, 0xc, 0x84, 0x5e, 0xff, 0xad, 0xa6, 0x32, 0x8, 0x63, 0x6, 0x35, 0x2b, 0x9b, 0x8e, 0xc7, 0x6d, 0xb7, 0xff, 0x6e, 0xff, 0x3d, 0xef, 0xb0, 0xe9, 0x30, 0xb0, 0x62, 0x8b, 0xd, 0x6e, 0x19, 0x7f, 0xbf, 0x2f, 0x7e, 0xdf, 0x15, 0x42, 0x11, 0xf6, 0x63, 0x58, 0x63, 0x59, 0x6c, 0x5b, 0xcb, 0x20, 0x6, 0x64, 0xe1, 0x0, 0x2c, 0xc, 0xdc, 0x40, 0xdd, 0x2c, 0xc8, 0x42, 0x0, 0x4, 0x5c, 0x63, 0x9b, 0xfc, 0xae, 0x1b, 0x2a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hslider_grabber_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc6, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x83, 0x83, 0x60, 0xaf, 0xb1, 0x65, 0xbb, 0xca, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x63, 0xb7, 0xc8, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x61, 0xb3, 0xbc, 0x60, 0xb1, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x63, 0xb4, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x69, 0x69, 0x5e, 0xb1, 0xcd, 0x5e, 0xb0, 0xcd, 0x36, 0x63, 0x63, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x60, 0xb2, 0xbd, 0x62, 0xb3, 0xbf, 0x3, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x9b, 0x9a, 0x52, 0x96, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x62, 0xb4, 0xbd, 0x63, 0xb7, 0xbf, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x51, 0x93, 0x92, 0x56, 0x9d, 0x9c, 0x0, 0x0, 0x0, 0x54, 0xa2, 0xc8, 0x4c, 0x94, 0xc2, 0x48, 0x8e, 0xc0, 0x47, 0x8c, 0xbf, 0x4b, 0x93, 0xc2, 0x4b, 0x92, 0xc2, 0x4f, 0x98, 0xc4, 0x4d, 0x96, 0xc3, 0x55, 0xa3, 0xc8, 0x53, 0x9f, 0xc7, 0x49, 0x8f, 0xc0, 0x4e, 0x97, 0xc4, 0x5a, 0xab, 0xcb, 0x5a, 0xac, 0xcc, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0xff, 0xff, 0xff, 0x6b, 0x1e, 0xb5, 0x61, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0xd, 0x1c, 0x27, 0x16, 0x6e, 0xc1, 0xef, 0xe8, 0x28, 0xf0, 0xf0, 0x22, 0xdb, 0xde, 0x24, 0x17, 0xaf, 0xc5, 0x1a, 0xa, 0x65, 0xfc, 0xfe, 0x64, 0xc, 0x31, 0xe0, 0xe0, 0x28, 0x2, 0x1, 0x14, 0x9c, 0x95, 0x13, 0x5, 0x2c, 0xdb, 0xdc, 0xb, 0x4f, 0xf4, 0xf7, 0x55, 0x73, 0x7d, 0x4, 0x28, 0xf1, 0xfd, 0xa1, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x41, 0x89, 0xde, 0x6c, 0x4e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x9e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0xcf, 0xd7, 0x12, 0x82, 0x30, 0x10, 0x5, 0x50, 0x48, 0x42, 0x12, 0xb0, 0x77, 0x8d, 0xd, 0xb, 0x28, 0x56, 0x12, 0x62, 0xd, 0x96, 0xff, 0xff, 0x2a, 0x61, 0xc, 0xe0, 0x83, 0xfb, 0xb4, 0xf7, 0xcc, 0xec, 0xcc, 0x5d, 0xc3, 0xf8, 0x37, 0x26, 0x80, 0x8, 0x41, 0x60, 0xe6, 0xd9, 0xc2, 0x84, 0x52, 0x82, 0xad, 0x4c, 0x0, 0xb6, 0xb9, 0x10, 0xdc, 0xc6, 0x40, 0x3, 0x24, 0x3c, 0x92, 0x32, 0xe2, 0x4, 0x6a, 0x40, 0x54, 0xc8, 0x64, 0x4, 0x45, 0x1a, 0x9c, 0xd2, 0x29, 0x85, 0x73, 0xd9, 0xd1, 0x50, 0xa9, 0x5e, 0x52, 0xb8, 0xd6, 0xea, 0x1a, 0x1a, 0xcd, 0x5b, 0xa, 0xf7, 0x56, 0x5b, 0x43, 0xa7, 0xdb, 0x53, 0x52, 0xaa, 0xfe, 0x80, 0x65, 0x3d, 0x86, 0xa3, 0x58, 0xca, 0x78, 0x3c, 0x99, 0x6a, 0x70, 0x67, 0xf3, 0x87, 0x52, 0xcf, 0xc5, 0x32, 0xaf, 0xee, 0xf9, 0xab, 0xd7, 0x7b, 0xed, 0x7b, 0xc5, 0x33, 0xc1, 0x66, 0xbb, 0xdb, 0xb3, 0x22, 0x27, 0x47, 0x87, 0xa3, 0xe5, 0xfe, 0xfe, 0x1b, 0x6, 0x2c, 0xfc, 0x6e, 0x1f, 0x93, 0x2a, 0x10, 0x62, 0x3, 0x21, 0x32, 0x75, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x83, 0x83, 0x60, 0xaf, 0xb1, 0x65, 0xbb, 0xca, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x63, 0xb7, 0xc8, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x61, 0xb3, 0xbc, 0x60, 0xb1, 0xbc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x63, 0xb4, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x69, 0x69, 0x5e, 0xb1, 0xcd, 0x5e, 0xb0, 0xcd, 0x36, 0x63, 0x63, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x60, 0xb2, 0xbd, 0x62, 0xb3, 0xbf, 0x3, 0x5, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0x9b, 0x9a, 0x52, 0x96, 0x95, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x62, 0xb4, 0xbd, 0x63, 0xb7, 0xbf, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x51, 0x93, 0x92, 0x56, 0x9d, 0x9c, 0x0, 0x0, 0x0, 0x54, 0xa2, 0xc8, 0x4c, 0x94, 0xc2, 0x48, 0x8e, 0xc0, 0x47, 0x8c, 0xbf, 0x4b, 0x93, 0xc2, 0x4b, 0x92, 0xc2, 0x4f, 0x98, 0xc4, 0x4d, 0x96, 0xc3, 0x55, 0xa3, 0xc8, 0x53, 0x9f, 0xc7, 0x49, 0x8f, 0xc0, 0x4e, 0x97, 0xc4, 0x5a, 0xab, 0xcb, 0x5a, 0xac, 0xcc, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0xd4, 0xd, 0x1d, 0x1c, 0x0, 0x0, 0x0, 0x31, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x3, 0xd, 0x1c, 0x27, 0x16, 0x6e, 0xc1, 0xef, 0xe8, 0x28, 0xf0, 0xf0, 0x22, 0xdb, 0xde, 0x24, 0x17, 0xaf, 0xc5, 0x1a, 0xa, 0x65, 0xfc, 0xfe, 0x64, 0xc, 0x31, 0xe0, 0xe0, 0x28, 0x2, 0x1, 0x14, 0x9c, 0x95, 0x13, 0x5, 0x2c, 0xdb, 0xdc, 0xb, 0x4f, 0xf4, 0xf7, 0x55, 0x73, 0x7d, 0x4, 0x28, 0xf1, 0xfd, 0xa1, 0x0, 0x0, 0x0, 0x7d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xcc, 0x81, 0x6, 0xc3, 0x40, 0x10, 0x84, 0xe1, 0xdd, 0x9d, 0xd9, 0x3d, 0x40, 0x1f, 0xa1, 0x0, 0xd1, 0xbe, 0xff, 0xbb, 0x94, 0x10, 0x29, 0x40, 0x1a, 0x40, 0x9, 0xa, 0xbd, 0x34, 0x7b, 0x39, 0xfa, 0x63, 0xf0, 0x61, 0x4c, 0xfe, 0xfa, 0x81, 0x1a, 0x48, 0x98, 0x36, 0x50, 0x66, 0xda, 0x40, 0x71, 0xab, 0x41, 0x3b, 0xc, 0x56, 0x1b, 0x3a, 0xd4, 0x8e, 0x4d, 0x8, 0x40, 0x6a, 0x64, 0x24, 0x0, 0xb6, 0x83, 0xa1, 0x1, 0x79, 0x0, 0x79, 0xc2, 0x54, 0x44, 0xca, 0x14, 0x91, 0xb0, 0xba, 0xef, 0xa7, 0xee, 0x9e, 0x70, 0x8d, 0xd0, 0x52, 0x2c, 0xe2, 0x99, 0x30, 0x93, 0xb, 0x7d, 0x81, 0x4a, 0x82, 0x8c, 0xc0, 0xba, 0xfa, 0x7b, 0x3c, 0x41, 0xb6, 0xd, 0x78, 0x84, 0x74, 0x98, 0x2f, 0x9f, 0xd7, 0x7d, 0x96, 0xbd, 0x2f, 0xa5, 0x6b, 0x13, 0xc4, 0x35, 0x90, 0x18, 0xcd, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hslider_tick_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xc3, 0x98, 0xc3, 0xc0, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x1e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x38, 0x55, 0x5f, 0x8c, 0xac, 0xb8, 0x81, 0xa2, 0xad, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x8d, 0x8d, 0x8d, 0x82, 0x82, 0x82, 0x4e, 0x4e, 0x4e, 0xff, 0xff, 0xff, 0xc1, 0xc9, 0xb1, 0x80, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x31, 0x79, 0x79, 0x1c, 0x7e, 0xed, 0x4b, 0xf4, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x9, 0xf1, 0xd9, 0xa5, 0xec, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x21, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x9, 0x60, 0x60, 0xb, 0x60, 0x60, 0xf, 0x60, 0x60, 0x6d, 0x60, 0x60, 0x14, 0x60, 0xc0, 0x4, 0x4c, 0x2, 0xc, 0xcc, 0x2, 0xc, 0x30, 0x65, 0x0, 0x46, 0x9d, 0x2, 0xbe, 0x9f, 0x3a, 0x6c, 0xab, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xc3, 0x98, 0xc3, 0xc0, 0x0, 0x0, 0x0, 0x1b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x38, 0x55, 0x5f, 0x8c, 0xac, 0xb8, 0x81, 0xa2, 0xad, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x8d, 0x8d, 0x8d, 0x82, 0x82, 0x82, 0x4e, 0x4e, 0x4e, 0xc9, 0xf6, 0x7, 0x31, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x31, 0x79, 0x79, 0x1c, 0x7e, 0xed, 0x4b, 0xf4, 0x0, 0x0, 0x0, 0x20, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x9, 0x60, 0x60, 0xb, 0x60, 0x60, 0xf, 0x60, 0x60, 0x6d, 0x60, 0x60, 0x14, 0x60, 0xc0, 0x4, 0x4c, 0x2, 0xc, 0xcc, 0x2, 0x70, 0x65, 0x0, 0x46, 0x9d, 0x2, 0xbe, 0xb7, 0xdf, 0x14, 0x38, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hsplit_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char hsplitter_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x40, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, 0x6f, 0x69, 0x56, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x27, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x80, 0x2, 0x66, 0x86, 0x5, 0xa2, 0xe7, 0x18, 0x16, 0x88, 0x9e, 0x63, 0x66, 0x10, 0xbd, 0xf6, 0x98, 0x41, 0xf4, 0xda, 0x63, 0x6, 0xc, 0x30, 0xaa, 0x66, 0x54, 0xd, 0x9a, 0x1a, 0x0, 0x5c, 0x29, 0x6a, 0x81, 0x90, 0x8f, 0x52, 0x12, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x40, 0x8, 0x0, 0x0, 0x0, 0x0, 0x2, 0x6f, 0x69, 0x56, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x1a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x80, 0x5, 0xa9, 0x10, 0xcc, 0x90, 0x6a, 0xd, 0xc6, 0x70, 0x80, 0x4b, 0xcd, 0xa8, 0x9a, 0x51, 0x35, 0x0, 0x78, 0xd5, 0x34, 0xa1, 0x54, 0x8c, 0xd5, 0x84, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_add_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0xa0, 0x25, 0x78, 0xf0, 0xe0, 0xc1, 0xff, 0x7, 0xf, 0x1e, 0xfc, 0xc7, 0xa7, 0x86, 0x89, 0x52, 0x4b, 0x46, 0xd, 0x60, 0x60, 0x60, 0x64, 0x60, 0x80, 0x84, 0x36, 0x39, 0x9a, 0x15, 0x14, 0x14, 0x18, 0x29, 0x76, 0x1, 0x5e, 0x30, 0x9a, 0xe, 0xe8, 0x64, 0x0, 0xc5, 0x0, 0x0, 0xc7, 0x6e, 0x12, 0x94, 0xf9, 0x26, 0x2e, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x3c, 0xf8, 0xff, 0xe0, 0xff, 0xd0, 0x52, 0x80, 0x10, 0xc4, 0xd, 0x9, 0x2a, 0x18, 0x26, 0xe1, 0x40, 0x18, 0x0, 0x0, 0x5b, 0x26, 0x61, 0x4d, 0xc9, 0xc1, 0x48, 0x81, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_close_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0xe, 0xc2, 0x30, 0x10, 0x4, 0x17, 0xaa, 0x3d, 0x67, 0xdb, 0x58, 0xd0, 0xd3, 0xf0, 0xa3, 0x7c, 0x36, 0x3c, 0x82, 0x48, 0x44, 0x22, 0x6f, 0xb1, 0x4d, 0x85, 0x14, 0x81, 0xf, 0x2c, 0x28, 0xe0, 0xda, 0xd5, 0x8c, 0x4e, 0x77, 0xb, 0xfc, 0xd5, 0x98, 0xd9, 0x20, 0x29, 0x7a, 0xb9, 0xa4, 0x68, 0x66, 0x83, 0xb, 0x93, 0xcc, 0x24, 0xa7, 0x9a, 0x44, 0x52, 0x24, 0x39, 0x91, 0xcc, 0x55, 0x89, 0xa4, 0xde, 0xcc, 0xce, 0x24, 0xb, 0xc9, 0x39, 0x84, 0xb0, 0xf7, 0xb2, 0xae, 0xeb, 0x76, 0xde, 0x8a, 0x4f, 0x92, 0x66, 0xd8, 0x91, 0x5c, 0x49, 0x5e, 0x9a, 0xe1, 0xb5, 0x64, 0x5, 0x16, 0x92, 0x8b, 0x7, 0x6f, 0x9b, 0x8c, 0x0, 0x4a, 0x29, 0x9b, 0x26, 0x81, 0xa4, 0x3e, 0xa5, 0x34, 0x2, 0x38, 0x2, 0x58, 0x0, 0xcc, 0x0, 0xe, 0x39, 0xe7, 0xd3, 0xfa, 0xb0, 0xee, 0xea, 0x8f, 0x7, 0x7b, 0xf5, 0x9d, 0xb7, 0xb0, 0x97, 0x55, 0x25, 0x5f, 0x17, 0xe9, 0x2e, 0xf9, 0xb8, 0xca, 0x3f, 0x9b, 0x1b, 0x1a, 0xe3, 0x40, 0x47, 0xa0, 0xda, 0xda, 0x61, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x62, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0xe0, 0x8c, 0xe0, 0x11, 0x43, 0xe6, 0xf3, 0x88, 0x71, 0x46, 0xa0, 0x48, 0x73, 0xfc, 0xe3, 0xb8, 0xcc, 0x23, 0x86, 0x90, 0xe6, 0xb8, 0xcc, 0xf1, 0xf, 0x49, 0x9, 0x8f, 0x28, 0xe7, 0x25, 0x8e, 0xff, 0x1c, 0xd7, 0xb9, 0x24, 0x91, 0x79, 0xdc, 0x12, 0x40, 0xe, 0xa6, 0x12, 0x54, 0x69, 0x4c, 0x25, 0xb7, 0x38, 0xae, 0x21, 0xa4, 0x31, 0x94, 0x80, 0x24, 0x81, 0xf0, 0x36, 0x48, 0x1a, 0xaf, 0x2, 0x88, 0x5b, 0xf0, 0x5a, 0x81, 0xa1, 0x4, 0xe1, 0x34, 0x84, 0x73, 0xb1, 0x4a, 0xa3, 0x7b, 0x9a, 0x70, 0x40, 0x11, 0xe, 0x6a, 0xca, 0x1, 0x0, 0x2a, 0x28, 0x37, 0x83, 0x3e, 0x27, 0xb0, 0x34, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_color_pick_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x1, 0x55, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xb5, 0x92, 0xb1, 0x4a, 0x3, 0x41, 0x14, 0x45, 0xef, 0xdb, 0x6c, 0xac, 0xf2, 0x1, 0xda, 0xcd, 0x40, 0x4, 0x25, 0x11, 0x4, 0x8b, 0x80, 0x8d, 0x20, 0x88, 0x5d, 0x20, 0x88, 0x90, 0x22, 0x9d, 0x9d, 0xa0, 0x85, 0x58, 0xeb, 0x7, 0x88, 0xe0, 0x7, 0x58, 0x8b, 0x36, 0x5a, 0x88, 0xa0, 0xa5, 0x85, 0xa5, 0x60, 0x61, 0xb0, 0x70, 0xb2, 0xef, 0x8d, 0x44, 0x41, 0x21, 0x1f, 0x20, 0x6c, 0xf2, 0x2c, 0xcc, 0xc2, 0x12, 0x92, 0x8d, 0x45, 0xbc, 0xe5, 0xdc, 0xb9, 0x67, 0xee, 0xbc, 0x19, 0xe0, 0xbf, 0xe5, 0xbd, 0x2f, 0x35, 0x9b, 0xcd, 0x29, 0x0, 0x10, 0x91, 0x9a, 0x88, 0x7c, 0x88, 0xc8, 0xa7, 0x88, 0xd4, 0x0, 0x80, 0xb2, 0xc2, 0xcc, 0x5c, 0x21, 0xa2, 0x5b, 0x22, 0xba, 0xef, 0x76, 0xbb, 0x97, 0x44, 0x74, 0x4a, 0x44, 0x61, 0xdf, 0xfe, 0x32, 0xc6, 0x4c, 0x87, 0x59, 0x0, 0x0, 0xdf, 0x0, 0x62, 0x55, 0xad, 0x6, 0x41, 0x50, 0x1d, 0xf0, 0x62, 0x0, 0x8, 0xb2, 0xd2, 0xd6, 0xda, 0x27, 0x0, 0x27, 0x83, 0xeb, 0xaa, 0x1a, 0x3, 0xd8, 0x19, 0xb, 0x60, 0xe6, 0x3a, 0x80, 0x6d, 0x0, 0xd, 0x0, 0x9d, 0x14, 0x60, 0xcb, 0x18, 0x73, 0x95, 0x9, 0x60, 0xe6, 0x3a, 0x11, 0x1d, 0xc7, 0x71, 0xbc, 0x6e, 0x8c, 0x39, 0x53, 0xd5, 0xdd, 0xc4, 0xcb, 0xe5, 0x72, 0x1b, 0xc9, 0x60, 0x87, 0x2, 0xd2, 0xe1, 0x62, 0xb1, 0xf8, 0xec, 0xbd, 0x2f, 0x11, 0xd1, 0x51, 0xaf, 0xd7, 0x3b, 0x0, 0xd0, 0x51, 0xd5, 0x95, 0x42, 0xa1, 0x30, 0x3b, 0xf2, 0x64, 0x11, 0x79, 0x77, 0xce, 0x95, 0x81, 0xdf, 0x67, 0x14, 0x91, 0x76, 0xff, 0x3a, 0x60, 0xe6, 0x45, 0x66, 0xae, 0xc, 0xd, 0x47, 0x51, 0xb4, 0x29, 0x22, 0xed, 0x56, 0xab, 0xb5, 0xd0, 0xdf, 0x3c, 0xe7, 0xbd, 0x7f, 0x8b, 0xa2, 0xa8, 0x31, 0x7a, 0x52, 0x93, 0x8, 0x8b, 0xc8, 0x72, 0xba, 0xb6, 0x73, 0xae, 0x9c, 0xae, 0x9d, 0xa5, 0x0, 0x0, 0x88, 0x68, 0xd, 0xc0, 0x8b, 0xaa, 0xbe, 0x3a, 0xe7, 0xca, 0x61, 0x18, 0xde, 0xa9, 0xea, 0xbe, 0xb5, 0xf6, 0x7c, 0x1c, 0x20, 0xf9, 0x89, 0x4b, 0x0, 0x56, 0xf3, 0xf9, 0xfc, 0xd, 0x80, 0x79, 0x55, 0xdd, 0xb3, 0xd6, 0x5e, 0x8c, 0xad, 0x9e, 0x0, 0x54, 0x75, 0x86, 0x88, 0xae, 0x1, 0x3c, 0x2, 0x38, 0x34, 0xc6, 0x3c, 0xfc, 0x25, 0x3c, 0x11, 0xfd, 0x0, 0x28, 0x54, 0xbb, 0xfe, 0xad, 0x99, 0xe5, 0xb8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xaa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x9d, 0x8e, 0x35, 0x82, 0x2, 0x41, 0x10, 0x45, 0x3b, 0xda, 0x3d, 0xca, 0xba, 0x44, 0x2b, 0x70, 0x9, 0xdc, 0xe1, 0x20, 0xe8, 0x91, 0x90, 0x78, 0x6e, 0x40, 0x4c, 0x82, 0x74, 0xff, 0xc2, 0x9d, 0x18, 0xa7, 0x6, 0x77, 0x7b, 0x23, 0x2d, 0xaf, 0x4c, 0xdc, 0xc, 0xbd, 0x65, 0x1e, 0x84, 0x80, 0x19, 0x55, 0x34, 0x60, 0x3e, 0xd0, 0xea, 0x17, 0x3d, 0x4a, 0xc8, 0x80, 0x1a, 0x60, 0xc2, 0x4f, 0xfd, 0x30, 0xe0, 0x1b, 0x2d, 0x16, 0xab, 0xa7, 0x2c, 0xe, 0x41, 0x68, 0xa5, 0xb9, 0xca, 0x91, 0x16, 0x2e, 0x54, 0xe0, 0x59, 0x54, 0x91, 0xfe, 0xa3, 0x3a, 0xff, 0xce, 0xab, 0x5b, 0xf, 0xa0, 0x4, 0x8f, 0x7b, 0x4c, 0xd3, 0x1b, 0xca, 0x32, 0xcc, 0x55, 0x7a, 0xf4, 0x76, 0x42, 0x2b, 0x97, 0x3e, 0xae, 0xfa, 0xdd, 0xd2, 0xd2, 0x8e, 0x72, 0xe1, 0x83, 0xaf, 0x9f, 0xa9, 0x28, 0x7d, 0x5b, 0xe2, 0x2a, 0xd, 0xc3, 0xa2, 0x78, 0xfe, 0x7d, 0x51, 0xfc, 0x0, 0x8a, 0x41, 0xcb, 0x3d, 0xb2, 0xae, 0x1c, 0xd3, 0xc, 0xa5, 0x30, 0x81, 0xc6, 0xda, 0x29, 0x8e, 0x83, 0x34, 0x25, 0x29, 0x4a, 0x46, 0x71, 0x1f, 0x33, 0xbe, 0x51, 0x89, 0xaf, 0x78, 0xe3, 0x97, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_folder_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xed, 0x8f, 0xc1, 0xd, 0x80, 0x30, 0x8, 0x45, 0x9f, 0x9d, 0x84, 0x39, 0x4c, 0x3b, 0xbd, 0x75, 0x8f, 0x32, 0x9, 0x5e, 0xec, 0xa5, 0x9, 0xa4, 0xc6, 0x26, 0x5e, 0x7c, 0x17, 0xe, 0xc0, 0xe3, 0x3, 0x5f, 0xb3, 0x1, 0xb4, 0xd6, 0x4e, 0x60, 0x77, 0x66, 0xaa, 0x88, 0x14, 0x4f, 0x90, 0xee, 0xea, 0x2d, 0x3, 0xe4, 0x28, 0x41, 0x8a, 0x9a, 0x1d, 0x55, 0x75, 0x25, 0xfd, 0x5, 0x9b, 0x11, 0xd, 0x54, 0x11, 0x29, 0x53, 0x9, 0x1c, 0x32, 0x4c, 0xbe, 0x10, 0xf1, 0xb, 0x16, 0xa, 0xea, 0xd3, 0x45, 0x33, 0x3b, 0xde, 0x1e, 0x5f, 0xc3, 0x5, 0x1f, 0xc5, 0x12, 0x2c, 0xc5, 0x88, 0xe1, 0xb4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x6, 0x78, 0x70, 0xf4, 0xc1, 0x7f, 0x24, 0x78, 0x18, 0x53, 0xc1, 0x7f, 0x54, 0x48, 0x50, 0xc1, 0x43, 0x1b, 0xbc, 0xa, 0x50, 0xad, 0x23, 0xa4, 0xe0, 0xff, 0x70, 0x52, 0x70, 0x18, 0x97, 0xf4, 0xfd, 0x43, 0xd4, 0x88, 0x4a, 0x0, 0x5a, 0xcb, 0x18, 0xab, 0x5e, 0xd9, 0x1a, 0x53, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_parent_folder_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0xc6, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xdd, 0x90, 0xbd, 0x6a, 0x2, 0x51, 0x10, 0x46, 0xcf, 0x8c, 0xbb, 0xaf, 0x10, 0xdb, 0xcb, 0x2e, 0x4b, 0x40, 0xf2, 0x14, 0x51, 0x8b, 0x3c, 0x70, 0x44, 0x48, 0x48, 0x15, 0x4c, 0x61, 0x67, 0xd2, 0x4, 0x96, 0xb, 0x5b, 0x89, 0x58, 0x59, 0xee, 0x8f, 0x3b, 0x36, 0xbb, 0x8d, 0x78, 0xa3, 0x92, 0x4a, 0x4f, 0xf9, 0xcd, 0xcc, 0x99, 0x61, 0xe0, 0xe6, 0x91, 0x50, 0xc1, 0x7b, 0x3f, 0x54, 0xd5, 0x39, 0x60, 0x6d, 0xdb, 0xbe, 0x24, 0x49, 0xb2, 0xb9, 0x58, 0x90, 0xe7, 0xf9, 0x43, 0x1c, 0xc7, 0xef, 0x66, 0xf6, 0xd4, 0x45, 0xbf, 0xc0, 0xb3, 0x73, 0x6e, 0x7d, 0x56, 0x70, 0x62, 0xb8, 0xe7, 0xa4, 0x44, 0x8f, 0xcf, 0x8e, 0xa2, 0xe8, 0xa3, 0x1b, 0xfe, 0xee, 0x62, 0x13, 0x91, 0x1f, 0xe0, 0x11, 0x78, 0xf3, 0xde, 0xf, 0x83, 0x2, 0x55, 0x9d, 0x1, 0x23, 0x60, 0xd5, 0x34, 0xcd, 0xb4, 0xcf, 0xab, 0xaa, 0x1a, 0x77, 0xc2, 0x91, 0xaa, 0xbe, 0x6, 0x5, 0xc0, 0xe, 0xf8, 0x2a, 0xcb, 0x72, 0x92, 0xa6, 0xe9, 0xb6, 0xf, 0xb3, 0x2c, 0xdb, 0xd6, 0x75, 0x3d, 0x11, 0x91, 0x25, 0x50, 0xfe, 0xf9, 0x83, 0x1e, 0x33, 0x93, 0xa2, 0x28, 0xf6, 0x80, 0x39, 0xe7, 0x6, 0xa1, 0xbe, 0xe3, 0xb, 0xae, 0x26, 0x28, 0x10, 0x11, 0x3, 0x16, 0x22, 0xf2, 0xf9, 0xdf, 0x25, 0xf7, 0xce, 0x1, 0x9e, 0x13, 0x48, 0xe9, 0x87, 0xc5, 0x3a, 0xd2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x68, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x33, 0xb8, 0x27, 0xfe, 0xe0, 0xfc, 0x83, 0x73, 0xf7, 0xc4, 0x71, 0x48, 0xdf, 0x11, 0x7b, 0x78, 0xe9, 0xc1, 0x3f, 0x20, 0xbc, 0xfe, 0x40, 0x12, 0x8f, 0x34, 0x4c, 0x9, 0xa6, 0xe1, 0x57, 0x80, 0x12, 0x17, 0x81, 0xf8, 0x2f, 0x58, 0xe1, 0x15, 0x34, 0x8b, 0x1e, 0x9c, 0x5, 0xa, 0x5e, 0xb8, 0x23, 0x6, 0x52, 0x70, 0x5b, 0x14, 0xac, 0xf0, 0xc, 0xaa, 0x82, 0x7d, 0xf, 0x8e, 0xde, 0x14, 0xf9, 0xcf, 0x8, 0x52, 0xc0, 0xc0, 0x70, 0x5b, 0xf4, 0xe1, 0xc9, 0x7, 0x47, 0xb1, 0xb8, 0x3, 0xaa, 0x0, 0xa, 0x48, 0x52, 0x80, 0xb0, 0xea, 0xc8, 0xc3, 0x83, 0xc, 0x83, 0xe, 0x0, 0x0, 0xb8, 0x27, 0x55, 0x4c, 0xbe, 0xc0, 0xd2, 0xac, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_play_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xa2, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0xf2, 0x80, 0x11, 0x99, 0xf3, 0xe0, 0xc1, 0x83, 0xc3, 0xc, 0xc, 0xc, 0xc2, 0xc, 0xc, 0xc, 0xa5, 0xa, 0xa, 0xa, 0x5b, 0xc9, 0x31, 0xe0, 0x3f, 0x5c, 0x82, 0x91, 0x71, 0x27, 0x3, 0x3, 0x43, 0x91, 0xbc, 0xbc, 0xfc, 0x35, 0x7c, 0x6, 0x30, 0xe1, 0x92, 0xf8, 0xff, 0xff, 0xbf, 0xfb, 0xff, 0xff, 0xff, 0x2f, 0x3e, 0x78, 0xf0, 0x60, 0xca, 0x93, 0x27, 0x4f, 0x84, 0x49, 0x76, 0x1, 0x1a, 0xf8, 0xc0, 0xc8, 0xc8, 0xd8, 0xf1, 0xeb, 0xd7, 0xaf, 0x9, 0xaa, 0xaa, 0xaa, 0x3f, 0x89, 0x72, 0x1, 0x1a, 0x10, 0xf8, 0xff, 0xff, 0x7f, 0x7, 0x2b, 0x2b, 0xeb, 0x1e, 0x74, 0x9, 0x62, 0xd, 0xc0, 0x9, 0x88, 0x35, 0xe0, 0x3d, 0x23, 0x23, 0x63, 0xc5, 0xef, 0xdf, 0xbf, 0x5d, 0xd0, 0x25, 0x58, 0x8, 0x68, 0xfc, 0xc3, 0xc0, 0xc0, 0x30, 0x93, 0x85, 0x85, 0xa5, 0x5e, 0x46, 0x46, 0xe6, 0x2d, 0x36, 0x5, 0x38, 0xd, 0x20, 0x36, 0x1a, 0xd1, 0xd, 0x38, 0xc2, 0x0, 0x4d, 0x48, 0xf2, 0xf2, 0xf2, 0x44, 0x25, 0xa4, 0x61, 0x0, 0x0, 0x1e, 0x57, 0x33, 0x3c, 0xcc, 0xe7, 0x34, 0x69, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x41, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x1b, 0x78, 0x70, 0xf8, 0xc1, 0xb5, 0x7, 0xde, 0xf8, 0x14, 0xfc, 0x7, 0xc1, 0x87, 0x3b, 0x1e, 0x6a, 0xe1, 0x54, 0x0, 0x85, 0xbf, 0x1f, 0x4c, 0x79, 0x22, 0x8c, 0x5d, 0x1, 0x2, 0xbe, 0x7f, 0x58, 0x7e, 0x9b, 0x1d, 0x43, 0x1, 0x1a, 0x3c, 0x4c, 0x91, 0x82, 0x77, 0x8, 0x2b, 0x8, 0x3b, 0x12, 0xd3, 0x9b, 0x84, 0x3, 0x8a, 0xfe, 0x0, 0x0, 0xa4, 0x15, 0x70, 0xca, 0x48, 0x40, 0x6f, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_reload_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x1, 0x59, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x31, 0x4b, 0x3, 0x31, 0x18, 0x86, 0x9f, 0x5c, 0xe, 0xec, 0x20, 0x76, 0x70, 0x39, 0xd0, 0xe3, 0xba, 0x74, 0x51, 0x41, 0xdd, 0xfc, 0x7, 0xba, 0xb8, 0x8, 0x52, 0xec, 0x2e, 0x4e, 0x3a, 0x88, 0x3f, 0xa3, 0xa3, 0x53, 0x7, 0x47, 0x67, 0x41, 0x17, 0xdd, 0x9c, 0x5c, 0x3b, 0xd8, 0x82, 0x64, 0x68, 0xca, 0xd5, 0x55, 0x11, 0x3c, 0x1a, 0x87, 0x24, 0x2e, 0xd7, 0x72, 0x9e, 0x9e, 0xab, 0xbe, 0xd3, 0xc7, 0x1b, 0x9e, 0x37, 0xf9, 0xbe, 0x7c, 0xf0, 0xd7, 0x12, 0x3f, 0x99, 0x4a, 0xa9, 0xb9, 0x30, 0xc, 0x8f, 0x84, 0x10, 0x7, 0xc0, 0x5a, 0x6e, 0x3f, 0x3a, 0xe7, 0x2e, 0xad, 0xb5, 0xdd, 0x66, 0xb3, 0xf9, 0x51, 0x19, 0x90, 0xa6, 0xe9, 0x92, 0xb5, 0xf6, 0x6, 0x58, 0xaf, 0xb8, 0xb4, 0x27, 0xa5, 0xdc, 0x8d, 0xe3, 0xf8, 0x19, 0x20, 0x28, 0xdf, 0x5c, 0x80, 0x53, 0x60, 0xdf, 0x18, 0x53, 0x37, 0xc6, 0xd4, 0xbd, 0xf7, 0x7b, 0xc0, 0x13, 0xb0, 0x61, 0xad, 0xbd, 0x56, 0x4a, 0xcd, 0x1, 0x84, 0xc5, 0x80, 0x30, 0xc, 0x8f, 0xa6, 0xb0, 0x94, 0x72, 0x33, 0x8e, 0xe3, 0x97, 0xc2, 0xf1, 0xd5, 0x68, 0x34, 0xba, 0xf7, 0xde, 0xf7, 0x80, 0xd, 0x29, 0xe5, 0x21, 0x70, 0xfe, 0xe5, 0x5, 0x42, 0x88, 0x76, 0x5e, 0x9e, 0x96, 0x60, 0x0, 0x92, 0x24, 0x79, 0x75, 0xce, 0x9d, 0x1, 0x4, 0x41, 0xd0, 0xfe, 0xd6, 0x2, 0xb0, 0x2, 0x60, 0x8c, 0xb9, 0xab, 0xe8, 0x1f, 0x6b, 0xed, 0x6d, 0x5e, 0xae, 0xce, 0x2, 0xb4, 0xd6, 0x17, 0x5a, 0x6b, 0x7, 0xcc, 0x3, 0xd4, 0x6a, 0xb5, 0x37, 0xad, 0xf5, 0xc5, 0x4f, 0x1, 0x41, 0x10, 0x7c, 0x19, 0x7c, 0x90, 0x3, 0xc7, 0xc0, 0xa0, 0xe0, 0xf, 0x72, 0xef, 0x9b, 0x84, 0x10, 0xdb, 0x79, 0xd9, 0x9f, 0x5, 0x44, 0x51, 0x94, 0x9, 0x21, 0x5a, 0x40, 0x6, 0x64, 0x42, 0x88, 0x56, 0x14, 0x45, 0x59, 0x19, 0x1e, 0x8f, 0xc7, 0x8b, 0x52, 0xca, 0xe, 0x80, 0x73, 0xee, 0x12, 0xa, 0xbf, 0x90, 0x24, 0x49, 0x7f, 0x38, 0x1c, 0x1e, 0x3, 0x34, 0x1a, 0x8d, 0x7e, 0x11, 0x54, 0x4a, 0x2d, 0x48, 0x29, 0x77, 0xac, 0xb5, 0x1d, 0xef, 0xfd, 0x32, 0xd0, 0x9b, 0x4c, 0x26, 0x5d, 0xa8, 0xd8, 0xc4, 0xb2, 0xf2, 0xf9, 0x4c, 0x55, 0xbd, 0x48, 0xbf, 0xe8, 0x1d, 0x78, 0x70, 0xce, 0x9d, 0x64, 0x59, 0xb6, 0x35, 0x85, 0xff, 0x87, 0x3e, 0x1, 0x53, 0x7, 0x87, 0x11, 0xd3, 0x3a, 0x9b, 0x9e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xb1, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x50, 0x35, 0xba, 0xc2, 0x40, 0x10, 0x7e, 0xcd, 0x33, 0x5c, 0xca, 0x1c, 0x21, 0x87, 0xc1, 0xa9, 0xd3, 0x23, 0x47, 0xca, 0x69, 0xb0, 0x6, 0x77, 0xdb, 0xfd, 0x17, 0x2f, 0x91, 0x3e, 0xee, 0xd2, 0xc1, 0x4e, 0xb5, 0xdf, 0xcc, 0xaf, 0x5f, 0x9f, 0x7c, 0xdb, 0x5f, 0xda, 0x44, 0x17, 0x2f, 0x75, 0xba, 0xa4, 0xb1, 0xfd, 0xf5, 0xad, 0x8f, 0x1c, 0x86, 0x90, 0x5c, 0x33, 0x38, 0x72, 0x1e, 0xb4, 0xbe, 0x66, 0x28, 0xad, 0xe2, 0xab, 0x38, 0xcd, 0x63, 0xa9, 0x9d, 0xb8, 0x58, 0x68, 0x53, 0x5b, 0x1f, 0x33, 0xd6, 0x9f, 0xa5, 0xc1, 0x20, 0x91, 0xba, 0x7d, 0x80, 0x1e, 0x24, 0x94, 0xdc, 0x92, 0xa4, 0x2, 0x9, 0x1d, 0xe7, 0xe0, 0x9, 0x69, 0x15, 0xf7, 0x58, 0x4e, 0x40, 0xc2, 0xc3, 0x58, 0x8a, 0xb6, 0x31, 0xd1, 0x39, 0xd8, 0x27, 0xed, 0x83, 0x5b, 0x14, 0x33, 0x7d, 0x3d, 0xbb, 0x45, 0x5d, 0x12, 0x55, 0x97, 0x4, 0xe3, 0xb5, 0xf4, 0x8c, 0x77, 0xd6, 0xa7, 0x2c, 0x3b, 0x78, 0x4c, 0x52, 0x81, 0xa, 0x8e, 0x3a, 0xa9, 0x6a, 0x6b, 0xc, 0xe6, 0x3f, 0xa1, 0x8d, 0x86, 0x16, 0xe5, 0x39, 0x78, 0xa2, 0x4d, 0xea, 0xe, 0xfa, 0xdd, 0xa7, 0x0, 0x90, 0x4f, 0x8b, 0xd0, 0xe1, 0x9e, 0x1b, 0xc2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_snap_grid_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc4, 0x0, 0x0, 0xe, 0xc4, 0x1, 0x95, 0x2b, 0xe, 0x1b, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0xc2, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xad, 0x90, 0xbd, 0xa, 0xc2, 0x30, 0x14, 0x85, 0xbf, 0x5b, 0x5c, 0x23, 0xe8, 0x6c, 0x9f, 0xc1, 0xb7, 0xd0, 0x47, 0xd1, 0x47, 0x70, 0x48, 0xa1, 0x43, 0x57, 0xe9, 0xd3, 0x88, 0x93, 0xef, 0xe0, 0xea, 0x5c, 0x9d, 0x1d, 0xb2, 0x96, 0xc6, 0xa1, 0x9, 0xd4, 0xd8, 0xd8, 0x4a, 0xfd, 0x20, 0x10, 0xee, 0xcf, 0xe1, 0xdc, 0x3, 0x1d, 0x8c, 0x31, 0xd6, 0x18, 0x63, 0x9, 0x88, 0xd5, 0x1, 0x92, 0xbe, 0xe2, 0x2f, 0x4c, 0x16, 0x90, 0x98, 0xb5, 0x21, 0x94, 0x52, 0xf2, 0x17, 0x7, 0x6f, 0x7c, 0xb, 0x2b, 0xc6, 0x64, 0x7, 0xb3, 0xa1, 0x1, 0x5b, 0x14, 0x29, 0x50, 0x2, 0x1b, 0x0, 0x44, 0x2e, 0x34, 0xcd, 0x41, 0xb2, 0xec, 0x6, 0x20, 0xdd, 0x61, 0x6f, 0xdf, 0x7, 0xe4, 0x96, 0xaf, 0xc0, 0x32, 0xd0, 0x7d, 0x2, 0x6b, 0xd1, 0xba, 0x4a, 0xfc, 0xdd, 0x91, 0xdb, 0x4b, 0xb7, 0x7c, 0x2, 0x56, 0xd4, 0x75, 0xa, 0x9c, 0x81, 0x5, 0x70, 0x84, 0xe1, 0xc, 0x5a, 0xdb, 0x75, 0xbd, 0x17, 0xad, 0x1f, 0x92, 0xe7, 0x77, 0x60, 0xe7, 0x7a, 0x5b, 0x80, 0x44, 0x29, 0x25, 0xfe, 0xf5, 0x8, 0x28, 0x0, 0xb7, 0xd8, 0x46, 0xa0, 0x75, 0xe5, 0xbe, 0xf3, 0x31, 0xe, 0x7e, 0x23, 0xcc, 0xc2, 0x3a, 0xc2, 0xb9, 0x58, 0xfd, 0x83, 0xc9, 0x2, 0x63, 0x78, 0x1, 0x4a, 0x50, 0x70, 0x86, 0xcc, 0x86, 0x2, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xf3, 0xf3, 0xf3, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x85, 0x85, 0xff, 0x83, 0x83, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x80, 0x80, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0x84, 0x84, 0xff, 0xff, 0xff, 0xa, 0xa5, 0x43, 0x1, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xff, 0x1d, 0xac, 0xf2, 0xaf, 0x27, 0xed, 0xff, 0xee, 0xb4, 0x1b, 0x1c, 0xb6, 0xaa, 0xf1, 0x50, 0xa6, 0xdd, 0x5f, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x0, 0x2, 0x40, 0x23, 0xd3, 0x60, 0x0, 0x40, 0xc, 0x3, 0xaf, 0x76, 0x93, 0xfd, 0x97, 0x7d, 0x9b, 0x55, 0x70, 0x12, 0x62, 0xaf, 0x68, 0x0, 0xc4, 0xe9, 0x3c, 0x1, 0x67, 0xf7, 0x17, 0x20, 0x95, 0xd6, 0xc6, 0xee, 0x80, 0x74, 0xde, 0x7b, 0x1f, 0x24, 0xb0, 0x64, 0x29, 0x1f, 0x53, 0x2e, 0xbe, 0x6e, 0x80, 0xf6, 0x19, 0x90, 0x9e, 0x36, 0x8b, 0xf7, 0xc0, 0x5c, 0xdf, 0x0, 0x66, 0x60, 0xae, 0xf3, 0xb9, 0x1, 0xfb, 0xe9, 0x1, 0xa6, 0x26, 0x1, 0xcd, 0x30, 0x66, 0x63, 0x6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_stop_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x2b, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x20, 0xc, 0x3e, 0x30, 0xe3, 0x93, 0x61, 0x64, 0x60, 0x60, 0x60, 0x78, 0xf8, 0x1f, 0xbb, 0x2, 0x79, 0x46, 0x6, 0x6, 0x26, 0x42, 0xe6, 0x8f, 0x2a, 0xa0, 0x96, 0x2, 0x6, 0x42, 0x91, 0x45, 0x10, 0x0, 0x0, 0x95, 0x31, 0x5, 0xe4, 0xe, 0x1, 0x8e, 0x3, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x2, 0x7c, 0x60, 0x26, 0x28, 0xf3, 0xf0, 0x3f, 0x76, 0x8, 0x94, 0xa2, 0x97, 0x82, 0x51, 0x5, 0x84, 0x23, 0x8b, 0x30, 0x0, 0x0, 0x66, 0x60, 0x11, 0xdc, 0x92, 0xb3, 0xb7, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_zoom_less_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x25, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0x5, 0xc3, 0x0, 0x30, 0x32, 0x30, 0x30, 0x30, 0x3c, 0x78, 0xf0, 0xe0, 0x3f, 0x39, 0x9a, 0x15, 0x14, 0x14, 0x18, 0x99, 0xa8, 0xeb, 0x9e, 0x51, 0x30, 0x44, 0x1, 0x0, 0xff, 0xa9, 0x4, 0x4, 0x4a, 0xae, 0x20, 0xfa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x13, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x31, 0xe0, 0xc1, 0x7f, 0x3c, 0x90, 0xb0, 0x82, 0x11, 0x2, 0x0, 0xbf, 0x57, 0x36, 0x25, 0x52, 0x24, 0x7b, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_zoom_more_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0xa0, 0x25, 0x78, 0xf0, 0xe0, 0xc1, 0xff, 0x7, 0xf, 0x1e, 0xfc, 0xc7, 0xa7, 0x86, 0x89, 0x52, 0x4b, 0x46, 0xd, 0x60, 0x60, 0x60, 0x64, 0x60, 0x80, 0x84, 0x36, 0x39, 0x9a, 0x15, 0x14, 0x14, 0x18, 0x29, 0x76, 0x1, 0x5e, 0x30, 0x9a, 0xe, 0xe8, 0x64, 0x0, 0xc5, 0x0, 0x0, 0xc7, 0x6e, 0x12, 0x94, 0xf9, 0x26, 0x2e, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x3c, 0xf8, 0xf, 0x84, 0x43, 0x4a, 0x1, 0x42, 0x10, 0xf, 0x24, 0xa8, 0x60, 0x78, 0x84, 0x3, 0x61, 0x0, 0x0, 0xca, 0x3a, 0x6d, 0x8d, 0x50, 0x1e, 0x9a, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char icon_zoom_reset_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xdd, 0x91, 0xbb, 0xd, 0x80, 0x30, 0x10, 0x43, 0x1f, 0x11, 0x23, 0x20, 0xea, 0x4c, 0xc5, 0x62, 0x48, 0xec, 0xc0, 0x56, 0x97, 0x26, 0x43, 0xa4, 0x31, 0x15, 0x12, 0x45, 0x72, 0x8a, 0x14, 0xa, 0x84, 0xab, 0xfb, 0x58, 0x3e, 0xeb, 0xc, 0x83, 0x98, 0xee, 0x22, 0xa5, 0xb4, 0x49, 0x3a, 0x1, 0x62, 0x8c, 0x53, 0x8d, 0x5c, 0xe3, 0x4, 0x80, 0x9c, 0xf3, 0x22, 0x69, 0xf7, 0x2e, 0xb5, 0x38, 0x1, 0xa0, 0x94, 0x72, 0x0, 0xab, 0x27, 0xd0, 0xc3, 0xc1, 0xcc, 0x64, 0x66, 0x6a, 0xf5, 0xb5, 0x59, 0x70, 0x15, 0x3b, 0x30, 0x7b, 0xcb, 0xd6, 0x33, 0x9f, 0x18, 0x76, 0xf0, 0x71, 0x81, 0x5a, 0xa, 0xaf, 0x3b, 0xf8, 0x41, 0xa, 0xc3, 0xb8, 0x0, 0x6c, 0x9c, 0x3f, 0xb8, 0x84, 0xfc, 0x5b, 0x85, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0xa, 0x3c, 0xc, 0x7b, 0xf0, 0xff, 0xc1, 0x7f, 0x9c, 0x22, 0xcf, 0x44, 0x1e, 0xbc, 0x84, 0x72, 0xb1, 0x8b, 0x3c, 0x58, 0x5, 0xe4, 0x40, 0xb8, 0x38, 0x45, 0x18, 0x60, 0x5c, 0x84, 0x30, 0x59, 0xa, 0xa0, 0x80, 0x6e, 0xa, 0x86, 0x92, 0x2f, 0x8, 0x3, 0x0, 0x69, 0xc8, 0x86, 0x87, 0x72, 0xca, 0x85, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char line_edit_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xd, 0xf6, 0xb4, 0x61, 0xf5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + +static const unsigned char line_edit_clear_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x90, 0x1, 0x6, 0xc0, 0x30, 0xc, 0x45, 0x77, 0x89, 0xd5, 0x76, 0xb3, 0x9e, 0x7b, 0x65, 0x63, 0xd, 0xf9, 0xbb, 0x48, 0x3b, 0xb3, 0x92, 0x54, 0x42, 0xb1, 0x5, 0x88, 0xf7, 0xc8, 0xcf, 0x9f, 0xfe, 0x1a, 0x8e, 0x14, 0xf4, 0x4e, 0x81, 0x63, 0x87, 0x51, 0x90, 0x28, 0x8, 0x46, 0x42, 0x51, 0x4a, 0x9e, 0x79, 0x43, 0xc5, 0x81, 0x55, 0x6f, 0xbc, 0x34, 0xdc, 0x2b, 0x2e, 0x16, 0xe5, 0x3a, 0xb1, 0xb, 0xb6, 0xca, 0x3, 0x2b, 0xb2, 0xc2, 0xbe, 0xf0, 0x66, 0x71, 0x4f, 0x70, 0x3b, 0x61, 0x14, 0x89, 0x26, 0x71, 0x5d, 0x6c, 0x9f, 0x1e, 0x17, 0x35, 0xae, 0xfa, 0xeb, 0xdc, 0x62, 0xc3, 0x84, 0x2d, 0x77, 0x22, 0xda, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char line_edit_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x95, 0xce, 0x31, 0x12, 0x2, 0x21, 0x10, 0x44, 0xd1, 0x3f, 0x40, 0xa1, 0x44, 0xa6, 0x46, 0xde, 0x63, 0x4f, 0xe5, 0x15, 0x38, 0xb2, 0xd6, 0x6, 0xb0, 0xc8, 0x30, 0x6, 0x96, 0xac, 0x56, 0x99, 0xf8, 0xb3, 0x7e, 0x51, 0xcb, 0xf9, 0x1a, 0xb3, 0x3f, 0xa, 0xaf, 0xc, 0xad, 0x2d, 0xcb, 0xe5, 0x76, 0x38, 0x5, 0x76, 0xec, 0x6c, 0xf7, 0xe0, 0x53, 0xe0, 0x13, 0xa1, 0x27, 0x27, 0x43, 0x26, 0x81, 0x20, 0xc8, 0x70, 0xfc, 0xe8, 0xf, 0x34, 0x67, 0xd8, 0x9c, 0x86, 0x61, 0x2e, 0x68, 0xe9, 0x91, 0xaf, 0x4b, 0x5a, 0x7d, 0x2a, 0x2c, 0x3, 0xed, 0xef, 0x1e, 0x6b, 0xcb, 0x4f, 0xa6, 0x66, 0x2b, 0x25, 0x6, 0x1, 0x37, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x94, 0xc8, 0x67, 0x6b, 0x60, 0xe6, 0x60, 0x64, 0x80, 0x80, 0xff, 0xc, 0x7f, 0x7f, 0xfc, 0x6a, 0x60, 0x94, 0xfb, 0xc0, 0xce, 0xcf, 0xc2, 0x80, 0x10, 0xfc, 0xc3, 0xf0, 0xf3, 0x23, 0xa3, 0xe2, 0x4f, 0xe, 0x36, 0x54, 0xc1, 0x1f, 0xbf, 0x18, 0x95, 0xbe, 0x73, 0x70, 0xb0, 0x30, 0xc0, 0x1, 0x48, 0xf0, 0x7, 0x85, 0x82, 0x58, 0x2d, 0xc2, 0xe6, 0xa4, 0x4f, 0x20, 0xc7, 0x37, 0x32, 0xb3, 0x23, 0x39, 0xfe, 0xfb, 0xaf, 0x46, 0x0, 0xee, 0x2a, 0x2f, 0xce, 0x4c, 0x47, 0x66, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char line_edit_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xab, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0xc8, 0x68, 0x12, 0xef, 0xed, 0xe7, 0xef, 0xed, 0xe8, 0xf0, 0xed, 0xe8, 0xf0, 0xee, 0xe8, 0xf0, 0xed, 0xe7, 0xed, 0xeb, 0xe5, 0xee, 0xeb, 0xe5, 0xee, 0xeb, 0xe6, 0xec, 0xe9, 0xe3, 0xeb, 0xe9, 0xe3, 0xeb, 0xe9, 0xe2, 0xec, 0xe9, 0xe2, 0xe9, 0xe6, 0xe0, 0xea, 0xe7, 0xe0, 0xea, 0xe7, 0xe1, 0xe8, 0xe4, 0xdd, 0xe8, 0xe5, 0xde, 0xe8, 0xe5, 0xdd, 0xe8, 0xe4, 0xde, 0xe6, 0xe2, 0xdb, 0xe6, 0xe3, 0xdb, 0xe6, 0xe3, 0xdc, 0xe7, 0xe2, 0xdb, 0xe7, 0xe3, 0xdb, 0xe4, 0xe0, 0xd8, 0xe5, 0xe0, 0xd8, 0xe5, 0xe1, 0xd9, 0xe5, 0xe0, 0xd9, 0xe4, 0xe1, 0xd9, 0xe5, 0xe1, 0xd8, 0xe4, 0xe0, 0xd9, 0xe2, 0xdf, 0xd6, 0xe3, 0xdf, 0xd6, 0xe3, 0xde, 0xd6, 0xe2, 0xde, 0xd6, 0xe1, 0xdc, 0xd4, 0xe1, 0xdc, 0xd3, 0xe0, 0xdc, 0xd3, 0xe1, 0xdd, 0xd3, 0xe1, 0xdd, 0xd4, 0xdf, 0xda, 0xd0, 0xdf, 0xda, 0xd1, 0xdf, 0xdb, 0xd1, 0xe0, 0xda, 0xd1, 0xdd, 0xd8, 0xcf, 0xdd, 0xd8, 0xce, 0xde, 0xd9, 0xce, 0xde, 0xd8, 0xce, 0xdd, 0xd9, 0xce, 0xdc, 0xd6, 0xcc, 0xdb, 0xd6, 0xcc, 0xdc, 0xd6, 0xcb, 0xff, 0xff, 0xff, 0x73, 0x72, 0x65, 0x6f, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x36, 0x61, 0xc5, 0x3a, 0xd, 0x83, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x38, 0xa0, 0x7, 0xa5, 0xd6, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x9e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x5d, 0xcf, 0xdb, 0x16, 0x82, 0x20, 0x10, 0x85, 0x61, 0xb4, 0xb4, 0x13, 0x1d, 0x28, 0x14, 0xcb, 0x4a, 0x33, 0xf, 0x59, 0x52, 0x98, 0x62, 0xef, 0xff, 0x66, 0xd1, 0xf6, 0xca, 0xfe, 0x19, 0xd6, 0x62, 0x7d, 0x77, 0x43, 0x88, 0x3d, 0x88, 0x10, 0x7b, 0x34, 0xc8, 0x36, 0x30, 0x76, 0x1c, 0x77, 0xe2, 0x3a, 0xee, 0xd4, 0x7c, 0x0, 0xb3, 0x79, 0x3f, 0xa6, 0x5, 0x80, 0xa2, 0x25, 0xa5, 0xab, 0x35, 0x5, 0x6c, 0x18, 0x63, 0x5b, 0xd6, 0x7, 0xd8, 0x71, 0xcf, 0xe3, 0x9c, 0xfb, 0x9c, 0x7b, 0x3e, 0x40, 0x4, 0xfb, 0xe0, 0x10, 0x84, 0xa1, 0x8, 0x85, 0x0, 0x1c, 0x4f, 0xe7, 0x28, 0xbe, 0x44, 0x71, 0x9c, 0x24, 0x67, 0xc0, 0x35, 0x4d, 0xb3, 0x2c, 0xcb, 0xcd, 0x4b, 0x73, 0x40, 0x71, 0x33, 0x15, 0xe5, 0xfd, 0x51, 0x16, 0x25, 0xa0, 0x92, 0xf2, 0xf9, 0x92, 0xbf, 0x2a, 0x9, 0x50, 0xaa, 0x56, 0xef, 0x46, 0xb5, 0x4d, 0x5b, 0x37, 0x0, 0xdd, 0x7d, 0xb4, 0x36, 0xdb, 0x69, 0xad, 0x1, 0x7f, 0xc7, 0x59, 0xc3, 0xf3, 0xad, 0x2f, 0x30, 0x4f, 0x11, 0x50, 0x3e, 0x12, 0x48, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xa8, 0x50, 0x4c, 0x54, 0x45, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0x1b, 0x17, 0x18, 0xc8, 0x68, 0x12, 0xef, 0xed, 0xe7, 0xef, 0xed, 0xe8, 0xf0, 0xed, 0xe8, 0xf0, 0xee, 0xe8, 0xf0, 0xed, 0xe7, 0xed, 0xeb, 0xe5, 0xee, 0xeb, 0xe5, 0xee, 0xeb, 0xe6, 0xec, 0xe9, 0xe3, 0xeb, 0xe9, 0xe3, 0xeb, 0xe9, 0xe2, 0xec, 0xe9, 0xe2, 0xe9, 0xe6, 0xe0, 0xea, 0xe7, 0xe0, 0xea, 0xe7, 0xe1, 0xe8, 0xe4, 0xdd, 0xe8, 0xe5, 0xde, 0xe8, 0xe5, 0xdd, 0xe8, 0xe4, 0xde, 0xe6, 0xe2, 0xdb, 0xe6, 0xe3, 0xdb, 0xe6, 0xe3, 0xdc, 0xe7, 0xe2, 0xdb, 0xe7, 0xe3, 0xdb, 0xe4, 0xe0, 0xd8, 0xe5, 0xe0, 0xd8, 0xe5, 0xe1, 0xd9, 0xe5, 0xe0, 0xd9, 0xe4, 0xe1, 0xd9, 0xe5, 0xe1, 0xd8, 0xe4, 0xe0, 0xd9, 0xe2, 0xdf, 0xd6, 0xe3, 0xdf, 0xd6, 0xe3, 0xde, 0xd6, 0xe2, 0xde, 0xd6, 0xe1, 0xdc, 0xd4, 0xe1, 0xdc, 0xd3, 0xe0, 0xdc, 0xd3, 0xe1, 0xdd, 0xd3, 0xe1, 0xdd, 0xd4, 0xdf, 0xda, 0xd0, 0xdf, 0xda, 0xd1, 0xdf, 0xdb, 0xd1, 0xe0, 0xda, 0xd1, 0xdd, 0xd8, 0xcf, 0xdd, 0xd8, 0xce, 0xde, 0xd9, 0xce, 0xde, 0xd8, 0xce, 0xdd, 0xd9, 0xce, 0xdc, 0xd6, 0xcc, 0xdb, 0xd6, 0xcc, 0xdc, 0xd6, 0xcb, 0xbd, 0x92, 0xbc, 0xa2, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x36, 0x61, 0xc5, 0x3a, 0xd, 0x83, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x4c, 0x8c, 0x55, 0x2, 0x4, 0x1, 0x8, 0x85, 0xc0, 0xc9, 0xfb, 0x1f, 0x76, 0x7b, 0x75, 0x3a, 0xf0, 0xc7, 0xc0, 0x27, 0xc1, 0x9d, 0x34, 0xe4, 0x4e, 0xb5, 0xa0, 0x68, 0x95, 0xf1, 0x93, 0xc4, 0xb0, 0xb7, 0xd6, 0x2, 0x7c, 0x2d, 0x46, 0xc3, 0x82, 0x45, 0xf8, 0x87, 0x16, 0x5a, 0xd7, 0x71, 0x21, 0x9e, 0x2c, 0x86, 0x52, 0x10, 0x89, 0xee, 0x86, 0x15, 0xd9, 0xf0, 0x6b, 0x7f, 0xac, 0x8b, 0xce, 0x85, 0xb4, 0x8b, 0xe1, 0xb7, 0x2e, 0x6, 0xd9, 0x53, 0x6a, 0x3c, 0x43, 0xa9, 0xd0, 0xcc, 0xd8, 0x5f, 0xd0, 0x4, 0xa2, 0xf6, 0x50, 0xac, 0x68, 0xff, 0x6d, 0xf9, 0x3f, 0xc, 0x93, 0x88, 0x59, 0x68, 0x81, 0x69, 0x18, 0x9e, 0x3, 0xba, 0x1b, 0x55, 0x0, 0x0, 0x0, 0x69, 0x26, 0x8d, 0xeb, 0x4b, 0xad, 0xe7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char logo_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc3, 0x3e, 0x61, 0xcb, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0x2e, 0x23, 0x0, 0x0, 0x2e, 0x23, 0x1, 0x78, 0xa5, 0x3f, 0x76, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdc, 0x9, 0x7, 0x13, 0x2, 0x0, 0x15, 0xb9, 0x53, 0x97, 0x0, 0x0, 0x21, 0x58, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x7d, 0x79, 0x9c, 0x1c, 0x55, 0xb5, 0xff, 0xf7, 0x7b, 0xab, 0x7b, 0x66, 0x48, 0x8, 0x61, 0xd1, 0x90, 0xb0, 0x88, 0x91, 0x27, 0x24, 0x24, 0x21, 0x3b, 0x8, 0x4, 0x42, 0x58, 0x54, 0xe0, 0x91, 0x80, 0x24, 0x1, 0x2, 0x9, 0x42, 0x80, 0x4, 0x11, 0x90, 0x9f, 0xf2, 0xd3, 0xa7, 0xcf, 0xe7, 0xf3, 0x3d, 0x1f, 0x1f, 0x7f, 0xea, 0xd3, 0x48, 0x4c, 0x8, 0x61, 0xd, 0x49, 0x64, 0x89, 0x82, 0x40, 0x58, 0x4, 0x64, 0xb, 0x44, 0x25, 0x9b, 0xd9, 0x51, 0x14, 0x41, 0x3, 0xc8, 0x16, 0x20, 0xfb, 0x4c, 0x77, 0xdd, 0xef, 0xef, 0x8f, 0xaa, 0xea, 0xae, 0xee, 0xa9, 0xea, 0x9e, 0xee, 0xae, 0x99, 0xe9, 0xe0, 0x9c, 0xf9, 0xd4, 0x74, 0xd5, 0xad, 0x5b, 0x77, 0x39, 0xe7, 0xdc, 0x7b, 0xcf, 0x39, 0xf7, 0xdc, 0x7b, 0x81, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xe8, 0x82, 0x2e, 0xf8, 0xe7, 0x2, 0x76, 0x76, 0x1, 0xea, 0x1, 0xe, 0xff, 0xc2, 0xcc, 0xbd, 0x60, 0x5b, 0x6e, 0xb6, 0xd6, 0xf6, 0x2, 0xb8, 0x8d, 0xc6, 0x6c, 0x36, 0x34, 0x6f, 0x81, 0x7c, 0x43, 0x30, 0x7f, 0x27, 0xcd, 0xdf, 0x8c, 0xe3, 0x6c, 0xda, 0x70, 0xef, 0xf4, 0x37, 0x3b, 0xbb, 0xac, 0x49, 0x43, 0xaa, 0xb3, 0xb, 0x50, 0xf, 0x20, 0x9b, 0xfd, 0x96, 0xcd, 0xb6, 0x4c, 0x40, 0xd0, 0x20, 0x2c, 0xac, 0x4b, 0xb3, 0x3, 0xc0, 0x36, 0x80, 0x5b, 0x41, 0x6c, 0x75, 0x5b, 0xb8, 0xed, 0xb0, 0x71, 0xff, 0xbb, 0x83, 0xc6, 0x6c, 0x26, 0x9d, 0x65, 0x74, 0xd2, 0x4f, 0x6e, 0x5c, 0x74, 0xc5, 0xba, 0xce, 0x2e, 0x7b, 0xad, 0xf0, 0x4f, 0xdf, 0x3, 0xf4, 0x9f, 0x38, 0xb7, 0x5b, 0x76, 0xd7, 0x7, 0x2f, 0xcb, 0xda, 0x3, 0xc8, 0x42, 0x94, 0x48, 0x6a, 0x15, 0x9f, 0x24, 0x0, 0xbe, 0x43, 0xe3, 0xfc, 0xc1, 0x49, 0x37, 0x4d, 0xdd, 0xf8, 0x8b, 0x2b, 0xff, 0xde, 0xd9, 0x75, 0xa8, 0x5, 0x76, 0x2b, 0x6, 0xe8, 0x37, 0x7e, 0xf6, 0x18, 0xeb, 0xb6, 0x9c, 0x6, 0x69, 0xf, 0x1a, 0xf3, 0xc1, 0x1f, 0xef, 0xbb, 0xe6, 0xdb, 0xb5, 0xa4, 0x37, 0xf2, 0x9a, 0xa5, 0xdc, 0xb2, 0x69, 0xe5, 0x69, 0xca, 0xec, 0xf8, 0xa5, 0xa4, 0x26, 0x48, 0xf2, 0x29, 0x8c, 0x82, 0x7b, 0x40, 0x3e, 0xae, 0xfc, 0x5f, 0x41, 0x82, 0x4d, 0x37, 0xf5, 0x18, 0xb7, 0xd7, 0xc1, 0xc3, 0x1f, 0xfe, 0xfd, 0x4f, 0x3e, 0xa3, 0x2a, 0x8b, 0xd0, 0xe9, 0x50, 0xf7, 0xc, 0x70, 0xf8, 0x39, 0xb3, 0x3e, 0x9, 0xb9, 0xa7, 0x48, 0xf6, 0x70, 0xb9, 0xd9, 0xd1, 0x90, 0x3b, 0xd2, 0x2b, 0x39, 0x9b, 0x4d, 0xaa, 0x69, 0xfa, 0x1f, 0xef, 0xbb, 0xfa, 0x8e, 0x5a, 0xd2, 0x3f, 0x6c, 0xdc, 0x8f, 0x9f, 0x91, 0xcd, 0x8c, 0x2, 0xe9, 0xe4, 0x43, 0x3, 0x7a, 0xc7, 0x80, 0x4, 0x80, 0xbb, 0x9c, 0x74, 0xd3, 0x77, 0xdd, 0xcc, 0xce, 0x1f, 0xbc, 0xfc, 0xd0, 0xd7, 0x6d, 0x67, 0xe3, 0xa9, 0x5a, 0xa8, 0x5b, 0x19, 0xa0, 0xdf, 0xf8, 0xd9, 0x47, 0x42, 0xee, 0x51, 0x72, 0x5b, 0x3e, 0x6b, 0xdd, 0xcc, 0x69, 0x0, 0xf6, 0xf4, 0x8, 0xe3, 0x75, 0xc3, 0x92, 0x1a, 0x6d, 0x66, 0xd7, 0x8f, 0xfa, 0x8d, 0x9f, 0xf5, 0xe7, 0x97, 0x7e, 0x71, 0xe5, 0xf3, 0x55, 0xe5, 0x31, 0xe1, 0xc6, 0x83, 0xdc, 0x5d, 0x5b, 0x46, 0x3, 0x7e, 0xb3, 0xce, 0x51, 0xbd, 0x74, 0xbb, 0xf0, 0x9b, 0xbb, 0x23, 0xd9, 0x23, 0x59, 0xf7, 0x4d, 0xa8, 0x34, 0xd4, 0x1d, 0x3, 0xf4, 0x3b, 0x67, 0xf6, 0x20, 0xc0, 0x1d, 0x65, 0xb3, 0xcd, 0x67, 0xc9, 0xcd, 0x9c, 0xa, 0x9f, 0x1a, 0xfe, 0xd8, 0x5b, 0xd0, 0x15, 0xb, 0xda, 0xcf, 0x66, 0x9a, 0x7f, 0xd8, 0x7f, 0xc2, 0x9c, 0xb1, 0x1b, 0x17, 0x4d, 0x7f, 0xa7, 0x92, 0x7c, 0xe, 0xff, 0xc2, 0xd, 0x69, 0x58, 0x77, 0x1c, 0x40, 0x17, 0x84, 0x3, 0x54, 0x48, 0x4a, 0xd2, 0x91, 0x75, 0x7, 0x38, 0x4d, 0x7b, 0xef, 0xd6, 0x2c, 0x50, 0x37, 0xc, 0xd0, 0x7f, 0xc2, 0x8d, 0x7, 0x3, 0x1a, 0x65, 0x33, 0xcd, 0x97, 0x58, 0x9b, 0x3d, 0x5, 0x0, 0x40, 0xe6, 0x5a, 0xa6, 0x82, 0x47, 0xbf, 0x13, 0x0, 0x21, 0x82, 0x90, 0xdc, 0xcf, 0xc8, 0x66, 0xbe, 0xd6, 0x6f, 0xfc, 0xac, 0xef, 0xbc, 0xf4, 0x8b, 0x2b, 0x77, 0xb5, 0x35, 0x3f, 0x93, 0x6a, 0xb4, 0x36, 0xb3, 0xe3, 0x7c, 0x1a, 0xe3, 0x8f, 0xe9, 0xe1, 0x21, 0x3f, 0x4, 0xe1, 0xd1, 0x40, 0x80, 0x24, 0xd1, 0x90, 0x10, 0x8c, 0x64, 0xf, 0x31, 0xa9, 0xa6, 0x2e, 0x6, 0x48, 0x2, 0x64, 0xb3, 0xdf, 0xb0, 0xd9, 0xe6, 0x2f, 0x1, 0x41, 0x6b, 0xf7, 0x9, 0x2f, 0x91, 0x1e, 0x23, 0x78, 0x40, 0x9f, 0x8, 0x34, 0x41, 0x90, 0x75, 0x33, 0xbb, 0xfe, 0xaf, 0xd3, 0xd0, 0x7d, 0xd9, 0x61, 0xe3, 0x7e, 0x78, 0xdf, 0x9f, 0x1e, 0xb8, 0x2e, 0x72, 0x3c, 0x1e, 0x30, 0xe9, 0xce, 0x94, 0xdb, 0xb2, 0x7d, 0x1f, 0xd2, 0xf4, 0x0, 0x6c, 0x1a, 0xb2, 0xbd, 0x65, 0xdd, 0xcf, 0x0, 0x30, 0x0, 0x41, 0x42, 0x91, 0xbd, 0x0, 0xb, 0xef, 0x49, 0x52, 0x9e, 0x7a, 0x40, 0x48, 0x7b, 0xee, 0x6, 0x62, 0x54, 0x49, 0xa8, 0x1b, 0x6, 0xb0, 0xd9, 0xcc, 0x39, 0x7e, 0x6b, 0xb, 0xda, 0x5c, 0xa8, 0xeb, 0x2f, 0x4, 0x7a, 0x81, 0x41, 0x3c, 0x3, 0x10, 0x36, 0xbb, 0xeb, 0xc7, 0x4e, 0x43, 0x8f, 0xd7, 0xfa, 0x4f, 0xb8, 0x71, 0x3, 0x68, 0xf6, 0x7, 0xb0, 0x37, 0x81, 0x34, 0x8, 0xca, 0xda, 0x46, 0xb7, 0x65, 0xeb, 0x27, 0x20, 0x3b, 0xd8, 0x75, 0xdd, 0xbe, 0x4, 0xf6, 0x83, 0x74, 0x30, 0x80, 0x40, 0xf0, 0x53, 0x25, 0x43, 0x0, 0xfd, 0xff, 0x22, 0xad, 0xcd, 0xee, 0xac, 0x59, 0x3, 0xe8, 0x7f, 0xee, 0x2d, 0xdd, 0x36, 0xde, 0x73, 0xe9, 0x8e, 0xce, 0xc0, 0x7b, 0xdd, 0x30, 0x0, 0x8d, 0xf3, 0xb2, 0xac, 0x3e, 0xe, 0xc0, 0x20, 0x4e, 0xc, 0xf, 0xc8, 0x1e, 0x3c, 0xf9, 0x8a, 0x3a, 0x49, 0x40, 0xf6, 0x60, 0xeb, 0xb6, 0xfc, 0x1f, 0xd2, 0xac, 0xb3, 0xb6, 0xf9, 0x24, 0x78, 0xad, 0xbb, 0x9b, 0x17, 0xb5, 0x90, 0x46, 0xca, 0x25, 0x46, 0x85, 0x52, 0x8e, 0xcb, 0xa7, 0x30, 0xdc, 0x4a, 0xa0, 0x21, 0xe8, 0x7d, 0xed, 0x36, 0x6f, 0xad, 0x89, 0x1, 0x8e, 0x38, 0x77, 0x6e, 0x5f, 0xeb, 0xb6, 0x9c, 0xde, 0x7f, 0xc2, 0x9c, 0xe7, 0x36, 0x2e, 0x9a, 0xbe, 0xb6, 0xc3, 0xf1, 0xde, 0xd1, 0x19, 0xc6, 0x41, 0xff, 0x9, 0xb3, 0xbf, 0x67, 0x33, 0xcd, 0x5f, 0x96, 0x6c, 0xcf, 0x70, 0xab, 0x8f, 0xa3, 0x43, 0x41, 0xb8, 0x4, 0x90, 0x16, 0x80, 0x41, 0xd8, 0x78, 0x43, 0x6, 0xef, 0x8a, 0xf4, 0x7a, 0x9, 0xf2, 0xfa, 0x7d, 0xff, 0xb1, 0x40, 0x0, 0x60, 0x51, 0xde, 0xc5, 0xf9, 0x11, 0x39, 0x23, 0x51, 0xd6, 0x69, 0xdc, 0xf3, 0x18, 0xc9, 0xbe, 0x61, 0x9c, 0x86, 0xad, 0x1b, 0xee, 0x9e, 0xba, 0xb5, 0xad, 0xf5, 0x3d, 0xe2, 0xbc, 0x5b, 0xbb, 0xc1, 0xba, 0x9f, 0xc8, 0x66, 0xb6, 0x2f, 0x86, 0x74, 0x28, 0x80, 0xb7, 0x4d, 0xba, 0xdb, 0xb9, 0xc6, 0x38, 0x4b, 0x37, 0xdc, 0x73, 0x59, 0x4b, 0x47, 0xe1, 0xbd, 0x6e, 0x18, 0xa0, 0xdf, 0x84, 0x39, 0xa7, 0x2b, 0xb3, 0x73, 0x2e, 0xa0, 0x3, 0x81, 0x60, 0x9c, 0x6f, 0x73, 0xb7, 0x1c, 0xc8, 0xb, 0x20, 0xf3, 0xad, 0x3a, 0xf4, 0x9c, 0x78, 0x3d, 0x95, 0x37, 0x13, 0x92, 0xc6, 0xf9, 0xb, 0x9d, 0xf4, 0x22, 0x63, 0x52, 0xb7, 0x3, 0x78, 0x3d, 0xdb, 0xbc, 0x6d, 0xe7, 0x9f, 0x1e, 0xf8, 0x6a, 0xac, 0x6d, 0xa0, 0xff, 0x84, 0x39, 0xfb, 0x4b, 0xee, 0x14, 0x9b, 0x69, 0xfe, 0x41, 0x90, 0x9a, 0x2f, 0x5b, 0xc0, 0xa4, 0x9b, 0xfe, 0xcd, 0x18, 0xe7, 0x96, 0xd, 0xf7, 0x4e, 0x7f, 0xb7, 0x23, 0xf0, 0x5e, 0x37, 0xc, 0xd0, 0xff, 0xdc, 0x9b, 0x3f, 0x65, 0x5b, 0xb6, 0x3f, 0x21, 0xd9, 0x4f, 0x41, 0x8, 0x24, 0xed, 0xb6, 0x95, 0x56, 0x65, 0xde, 0x25, 0x55, 0x53, 0x3f, 0xad, 0x9c, 0x26, 0xe0, 0x3f, 0x14, 0xf4, 0x1e, 0x26, 0x75, 0x3f, 0x9d, 0x86, 0x9f, 0xd2, 0x49, 0xaf, 0xec, 0xd1, 0xfb, 0x88, 0x6d, 0xc5, 0x56, 0xc2, 0xfe, 0x13, 0x6f, 0x3a, 0xcc, 0x66, 0x9b, 0xe7, 0x40, 0xee, 0x18, 0x0, 0x5e, 0xaf, 0x15, 0x24, 0x3, 0x8, 0x24, 0x8d, 0xd3, 0x70, 0x13, 0x4c, 0xea, 0xfb, 0x1b, 0xef, 0x9d, 0xf6, 0x6a, 0x7b, 0xe3, 0xdd, 0xb4, 0x77, 0x6, 0x6d, 0x85, 0x8d, 0xf7, 0x5c, 0xf6, 0xa, 0x69, 0x9a, 0x3d, 0x51, 0x3b, 0xc0, 0x26, 0xfd, 0xb, 0xa5, 0x9, 0x58, 0xaa, 0xa3, 0x28, 0xf7, 0x6d, 0x25, 0xe0, 0xa7, 0x95, 0x27, 0x3e, 0x94, 0xcf, 0xc0, 0xd3, 0x26, 0xad, 0x9b, 0x3d, 0xdb, 0x6d, 0xd9, 0xf1, 0x8c, 0x6d, 0xd9, 0xfe, 0xdc, 0x96, 0xd7, 0x57, 0x9f, 0x11, 0xfe, 0xfc, 0x88, 0x73, 0xe7, 0x9e, 0xec, 0xb6, 0xec, 0xd8, 0x28, 0xeb, 0x8e, 0xf1, 0xbe, 0xf5, 0xf1, 0x2f, 0x88, 0xa0, 0xcf, 0x48, 0xb4, 0xd6, 0x6d, 0x99, 0x66, 0xb3, 0x2d, 0xf3, 0xfb, 0x4f, 0x9c, 0x7b, 0x5c, 0x7b, 0xe3, 0xbd, 0x6e, 0x7a, 0x0, 0x0, 0xe8, 0x77, 0xce, 0xcf, 0x9e, 0xb3, 0x6e, 0xe6, 0x78, 0x20, 0x5a, 0xfa, 0xaf, 0x3f, 0x8, 0x86, 0x81, 0x7c, 0x61, 0xfd, 0x91, 0x41, 0x64, 0xa0, 0x5a, 0x38, 0x2b, 0x4c, 0xba, 0xf1, 0x3b, 0x4, 0x7a, 0x66, 0x5b, 0x76, 0x2c, 0xf4, 0xf8, 0xbb, 0xd5, 0xb0, 0x54, 0xd0, 0x4f, 0x5, 0x6a, 0x26, 0x8d, 0x79, 0x8d, 0x4e, 0xd3, 0xbf, 0xbd, 0xb4, 0x68, 0xda, 0x5d, 0xed, 0x55, 0x3, 0xa7, 0xf6, 0x24, 0x92, 0x83, 0x8f, 0xf, 0x1c, 0x9b, 0x2, 0x34, 0x9c, 0x40, 0x8f, 0x78, 0xcb, 0x4c, 0x3d, 0x41, 0xd0, 0x45, 0xf9, 0xe0, 0xcb, 0x2d, 0xbe, 0xd5, 0x92, 0x14, 0x24, 0xa2, 0xb7, 0x6c, 0x76, 0x82, 0xac, 0x7b, 0x16, 0x29, 0x27, 0x50, 0x21, 0x1, 0x85, 0xba, 0xba, 0x5c, 0x37, 0xe2, 0xdb, 0xbb, 0x72, 0x36, 0xb0, 0xbd, 0x61, 0xdd, 0x13, 0xf7, 0x3f, 0xf2, 0xec, 0x96, 0x77, 0xd6, 0x2f, 0xfe, 0x5d, 0x7b, 0xd4, 0xa0, 0x6e, 0x86, 0x0, 0xaf, 0x34, 0xce, 0x12, 0x0, 0xef, 0x7b, 0xf7, 0x86, 0xf9, 0x21, 0x60, 0x37, 0xb9, 0x8c, 0xf1, 0x94, 0xc3, 0x80, 0x71, 0x69, 0x40, 0xd2, 0x90, 0x6c, 0x0, 0xd4, 0x0, 0x18, 0x79, 0x17, 0x8, 0x18, 0x45, 0xa4, 0xe1, 0x31, 0x81, 0x31, 0xfe, 0x7b, 0x3, 0x40, 0xfb, 0x65, 0x33, 0xbb, 0xbe, 0xde, 0x6f, 0xc2, 0x9c, 0xaf, 0xb4, 0x7, 0xca, 0xeb, 0xa6, 0x7, 0xe8, 0x3f, 0x71, 0xee, 0x4, 0x4f, 0x38, 0x52, 0x3f, 0xf8, 0xb6, 0x9e, 0xd0, 0xe8, 0xba, 0xfb, 0x5c, 0x44, 0xae, 0xfd, 0xe7, 0xee, 0x1, 0xbf, 0x67, 0x80, 0x7f, 0x11, 0xa1, 0x77, 0x45, 0xdf, 0x93, 0xa1, 0x74, 0x82, 0x1e, 0x61, 0x4f, 0xca, 0xe, 0xea, 0x35, 0xe8, 0x2c, 0xe7, 0x9d, 0xf5, 0x8b, 0x97, 0x26, 0x89, 0xf7, 0xba, 0x30, 0x4, 0xf5, 0x9f, 0x78, 0xd3, 0x2c, 0x9b, 0xdd, 0x75, 0x36, 0xa0, 0x3e, 0xde, 0x18, 0x69, 0x24, 0x28, 0x6c, 0x0, 0xde, 0x1d, 0x81, 0x31, 0xf7, 0x6d, 0x6, 0x6f, 0x14, 0xf4, 0x70, 0x21, 0xb0, 0x1b, 0xc8, 0xee, 0x49, 0x17, 0xb2, 0xd3, 0x19, 0xe0, 0xf0, 0x73, 0x66, 0x3d, 0xad, 0x6c, 0xcb, 0x48, 0x0, 0xdd, 0xbd, 0x39, 0x1e, 0xdf, 0x74, 0x53, 0xef, 0xc3, 0x7f, 0x87, 0x40, 0xce, 0xe4, 0xd, 0x1a, 0x67, 0xb5, 0x71, 0xd2, 0xd7, 0x27, 0x9d, 0x43, 0x62, 0xc, 0x70, 0xc4, 0xb9, 0x73, 0x7f, 0x24, 0x61, 0x1b, 0x8d, 0xf3, 0xd3, 0xd, 0x77, 0x4f, 0x7d, 0xbf, 0x5c, 0xfc, 0x81, 0x93, 0xee, 0xd8, 0x23, 0xdb, 0xb2, 0xe3, 0x31, 0xd9, 0xec, 0x9, 0x5e, 0x3f, 0x97, 0x13, 0x80, 0xbb, 0x88, 0xef, 0x83, 0x6f, 0xc0, 0x24, 0xe9, 0xbc, 0x63, 0x9c, 0xf4, 0xe2, 0x75, 0x3f, 0xbf, 0x38, 0x71, 0xb, 0x61, 0x22, 0x98, 0x3e, 0xe2, 0xbc, 0x5b, 0x47, 0xd8, 0xcc, 0xce, 0x7, 0x25, 0x75, 0xa3, 0x71, 0xd6, 0x80, 0xe6, 0x75, 0xd2, 0xfc, 0x99, 0xc6, 0x99, 0xb7, 0xe1, 0xee, 0xa9, 0x7f, 0x2e, 0x8e, 0xdf, 0xff, 0xdc, 0x5b, 0xe, 0x95, 0xdb, 0x72, 0x87, 0x6c, 0x76, 0x14, 0xe9, 0xab, 0xc2, 0x5e, 0x4d, 0xe1, 0x49, 0xc7, 0x51, 0xc5, 0x8c, 0x33, 0xb9, 0x87, 0xe7, 0x85, 0x54, 0xe2, 0x9b, 0x62, 0x3, 0x6f, 0xb9, 0xb4, 0x63, 0xb5, 0xb4, 0x88, 0xf0, 0xa8, 0xef, 0x2a, 0x29, 0x6f, 0xeb, 0x6f, 0x72, 0xbe, 0x67, 0x0, 0x41, 0xe7, 0x91, 0x74, 0xd3, 0x9e, 0xe3, 0xd7, 0x2e, 0x98, 0xb2, 0xb3, 0x1a, 0xfa, 0x94, 0x82, 0x9a, 0x19, 0xe0, 0x88, 0xf3, 0xe7, 0xf5, 0x50, 0x76, 0xc7, 0xc3, 0xb2, 0xee, 0x71, 0x80, 0x42, 0x5a, 0x85, 0xd9, 0x42, 0x63, 0xd6, 0x80, 0xce, 0x4a, 0x1a, 0xe7, 0x77, 0x26, 0x95, 0x7e, 0x74, 0xdd, 0x82, 0x29, 0x1f, 0x1c, 0x71, 0xfe, 0x6d, 0x43, 0x6c, 0x66, 0xd7, 0x4d, 0x90, 0x7b, 0x54, 0xa8, 0x18, 0xc2, 0x6e, 0x3e, 0xe0, 0x27, 0xa, 0xca, 0xd9, 0x1c, 0x9, 0x3a, 0xaf, 0x9a, 0x54, 0xc3, 0xbf, 0x6f, 0xb8, 0xfb, 0xd2, 0x85, 0xed, 0x91, 0x55, 0xcd, 0x43, 0x80, 0xdc, 0xe6, 0x1f, 0xcb, 0xba, 0xbe, 0xf1, 0xc6, 0x84, 0xed, 0xf0, 0x7b, 0xc9, 0xba, 0xa3, 0x0, 0x77, 0x94, 0xac, 0x73, 0x86, 0xac, 0x3b, 0xae, 0xff, 0xc4, 0xb9, 0x7f, 0x57, 0xb6, 0x79, 0x38, 0x64, 0x8f, 0xf2, 0x6c, 0xf4, 0xb9, 0x7e, 0xdf, 0x17, 0xf8, 0xca, 0xb5, 0xe0, 0xb6, 0x98, 0xf5, 0x2b, 0x69, 0x95, 0xc5, 0x3e, 0x9f, 0xe1, 0xfb, 0x72, 0x71, 0xdb, 0x52, 0xd6, 0xf0, 0x77, 0x71, 0xe5, 0x2c, 0xec, 0x11, 0x3c, 0xe9, 0x97, 0xb9, 0xf9, 0x26, 0x1a, 0xe7, 0xa9, 0xc6, 0x6e, 0x3d, 0xef, 0xa9, 0x95, 0x4e, 0x71, 0x50, 0x53, 0xab, 0x1b, 0x70, 0xfe, 0x6d, 0x5f, 0xb0, 0x99, 0x9d, 0xbf, 0x90, 0x37, 0x8b, 0x9f, 0xa3, 0x62, 0x48, 0x82, 0x97, 0x82, 0x3c, 0xa, 0x3c, 0xee, 0x68, 0x25, 0x85, 0xad, 0xfd, 0x5d, 0xad, 0x3f, 0x4, 0x9e, 0x25, 0x90, 0x34, 0x4e, 0xea, 0x45, 0x3a, 0xd, 0xd7, 0xad, 0xbf, 0xeb, 0xe2, 0xe7, 0xda, 0x2b, 0xaf, 0xaa, 0x7b, 0x80, 0x81, 0x93, 0xee, 0x38, 0xd8, 0xcd, 0xec, 0xfc, 0xbe, 0x2, 0xa3, 0x95, 0xef, 0x58, 0xc5, 0x90, 0xff, 0x4e, 0xce, 0x98, 0x27, 0x8, 0x26, 0x4f, 0x64, 0x8f, 0xf8, 0x7e, 0xb7, 0x5f, 0xcd, 0x5c, 0x5d, 0x12, 0xf3, 0x7b, 0xd5, 0xb0, 0x5e, 0xa9, 0x6f, 0x8a, 0x1c, 0xc7, 0x2b, 0xae, 0x47, 0xe1, 0x77, 0xde, 0x9d, 0x71, 0xee, 0x69, 0x4f, 0xe2, 0x3, 0x55, 0x5a, 0x2, 0x7, 0x4c, 0x9a, 0xd7, 0x60, 0x6d, 0xf6, 0x5a, 0x59, 0xfb, 0x69, 0x7f, 0xf2, 0xc6, 0x9b, 0x5d, 0x2f, 0x12, 0xdf, 0x73, 0xcf, 0x45, 0xe3, 0xbb, 0x37, 0xe7, 0x91, 0x73, 0xac, 0xa9, 0x1c, 0x2a, 0xfc, 0x46, 0x2a, 0xe8, 0x9f, 0x15, 0xfc, 0x13, 0x50, 0xe0, 0x3e, 0x20, 0x95, 0x49, 0xa8, 0xd4, 0xc4, 0x12, 0x8b, 0x7e, 0x2b, 0xad, 0x7, 0x8b, 0x5f, 0x30, 0x5e, 0x8e, 0x4c, 0x10, 0x2a, 0x66, 0x80, 0x81, 0x17, 0xce, 0x77, 0x20, 0x3b, 0xda, 0x66, 0x5b, 0xae, 0xcd, 0x9b, 0xc1, 0xc3, 0x53, 0x76, 0x9d, 0x7b, 0x29, 0x34, 0x43, 0xe7, 0xdf, 0xfb, 0x73, 0xed, 0x1e, 0x81, 0x25, 0xd0, 0x37, 0x34, 0xe4, 0xae, 0xe0, 0x1d, 0xa3, 0x6d, 0x73, 0xf2, 0xd3, 0xca, 0xdd, 0xb7, 0xff, 0xe5, 0x33, 0xa9, 0xdc, 0x2f, 0xc, 0x98, 0x74, 0xc7, 0xf1, 0xed, 0xc9, 0x0, 0x15, 0xb7, 0xbf, 0x41, 0x17, 0xce, 0xef, 0x93, 0x6d, 0xd9, 0xf9, 0x0, 0xac, 0x3b, 0xd2, 0xeb, 0xc0, 0xe3, 0x54, 0xb7, 0x4a, 0x8a, 0x50, 0x4a, 0x65, 0x2, 0x4a, 0xb, 0x5c, 0x39, 0xc8, 0x77, 0xa2, 0xa, 0xd4, 0xa7, 0x82, 0xb4, 0x3e, 0x0, 0xf9, 0x3e, 0x80, 0x6d, 0x0, 0x76, 0x92, 0xdc, 0x5, 0xd2, 0x42, 0x8, 0xe4, 0x91, 0x14, 0x80, 0x26, 0x9, 0xdd, 0x20, 0xbb, 0xf, 0xa0, 0x5e, 0x90, 0x6f, 0x2a, 0x67, 0x4c, 0x1e, 0x35, 0x6b, 0x2e, 0x11, 0xf5, 0x93, 0xe7, 0x13, 0x0, 0xc2, 0x42, 0x32, 0x34, 0xce, 0x93, 0x26, 0xd5, 0x78, 0xd9, 0xba, 0x85, 0x17, 0xbd, 0x5a, 0x5b, 0x5e, 0xa5, 0x4b, 0xd0, 0x26, 0x18, 0x7c, 0xc5, 0x33, 0xcc, 0x7e, 0xf8, 0xea, 0x19, 0x36, 0xb3, 0xf3, 0x21, 0x0, 0x16, 0x81, 0x12, 0x1f, 0xae, 0x8a, 0xe2, 0x13, 0x2d, 0x18, 0xf2, 0x22, 0x4, 0xe7, 0x3c, 0xef, 0x7, 0xe6, 0xaf, 0xfc, 0x87, 0xad, 0xc8, 0xee, 0x8b, 0x1d, 0xa, 0xd6, 0x8a, 0x84, 0xe6, 0x66, 0xfd, 0x98, 0x2d, 0x34, 0xce, 0x3f, 0x24, 0xbc, 0x4d, 0x9a, 0x4d, 0x30, 0x66, 0x1d, 0xc0, 0x97, 0x48, 0xfe, 0x15, 0xe0, 0x3b, 0x20, 0xdf, 0x23, 0xd4, 0xec, 0x5a, 0x65, 0xd2, 0xe9, 0x86, 0x46, 0xeb, 0x66, 0xba, 0x1, 0xd8, 0xd7, 0x5a, 0xdb, 0x7, 0xd2, 0x0, 0xc9, 0x8e, 0x24, 0x74, 0xb0, 0xa4, 0x8f, 0x1, 0x3a, 0x0, 0xb2, 0xfb, 0x86, 0xab, 0xc2, 0x90, 0xcf, 0x7a, 0x1, 0x33, 0xa8, 0x75, 0x7d, 0xa, 0xe4, 0xfd, 0x8, 0x33, 0x40, 0x41, 0x13, 0xa, 0x3b, 0xc6, 0x7a, 0x35, 0xb2, 0x74, 0x1a, 0xe6, 0x34, 0xef, 0xdc, 0x7e, 0xd5, 0x5f, 0x1e, 0xb8, 0x3a, 0xf1, 0x15, 0x48, 0x15, 0x9, 0x81, 0xee, 0x96, 0xbf, 0xd, 0x92, 0xdb, 0xf2, 0x7d, 0x80, 0xa0, 0x6f, 0xb0, 0xf7, 0xb0, 0x9f, 0x9b, 0xb7, 0x40, 0xde, 0x23, 0xab, 0x88, 0x82, 0xb9, 0xa7, 0xd0, 0xff, 0x1c, 0xc5, 0x43, 0x2c, 0xc3, 0xa8, 0xc6, 0xdb, 0x2a, 0x2c, 0xb0, 0x93, 0x4, 0x62, 0x86, 0xfc, 0x29, 0x78, 0x80, 0x7c, 0xf, 0x30, 0x9b, 0x4, 0xb3, 0x96, 0x4e, 0x6a, 0x71, 0x3a, 0xd5, 0xf0, 0xe0, 0xea, 0x3b, 0x27, 0x95, 0x33, 0xa0, 0xb4, 0x0, 0xd8, 0xa, 0xe0, 0x2d, 0x0, 0x1b, 0x1, 0x3c, 0x15, 0xbc, 0x18, 0x30, 0xe9, 0xce, 0x7e, 0xb2, 0x99, 0x89, 0x80, 0x8e, 0x83, 0xec, 0xa1, 0x92, 0x3d, 0x8, 0x42, 0x63, 0xa0, 0xc1, 0x7a, 0x79, 0x2a, 0x50, 0x79, 0x42, 0x66, 0xcc, 0xbc, 0xab, 0x40, 0x58, 0xd, 0xca, 0xd7, 0x3b, 0xa8, 0x17, 0xfc, 0x70, 0xbf, 0x4a, 0xfe, 0xa, 0x88, 0xc0, 0x30, 0x26, 0xc1, 0x48, 0xee, 0x99, 0x4d, 0xdd, 0xf7, 0x5a, 0xe, 0xe0, 0xf6, 0xa4, 0x19, 0xa0, 0xa2, 0x1e, 0x60, 0xe0, 0x5, 0x77, 0x9e, 0xea, 0x66, 0x76, 0x3e, 0x26, 0xc9, 0x84, 0xb1, 0xdf, 0x91, 0x10, 0xb2, 0x15, 0xcb, 0xd7, 0x32, 0x7c, 0xe, 0xe0, 0xfb, 0x24, 0xdf, 0xa2, 0x49, 0xdd, 0x6c, 0x1c, 0x67, 0xf6, 0xda, 0x5, 0x53, 0xda, 0xbc, 0x48, 0xa4, 0xad, 0x30, 0x60, 0xd2, 0xbc, 0x43, 0x21, 0xf7, 0xbb, 0x92, 0x1d, 0x29, 0xeb, 0x7e, 0x2, 0x52, 0x93, 0xbf, 0x4c, 0x2d, 0xd4, 0x10, 0x12, 0xad, 0x6b, 0xde, 0xa7, 0x91, 0xce, 0x12, 0xa6, 0xf6, 0x38, 0x75, 0xfd, 0xc2, 0xb, 0x9a, 0x93, 0xcc, 0xa3, 0x32, 0x6, 0x98, 0x7c, 0x57, 0xa3, 0xcd, 0x36, 0x9f, 0x23, 0xb7, 0xe5, 0x4e, 0x40, 0x4e, 0xe0, 0x80, 0xd9, 0x51, 0xf6, 0xfb, 0x80, 0xf8, 0x61, 0x84, 0x4b, 0xd8, 0x49, 0x60, 0x87, 0x49, 0x37, 0x7e, 0x7b, 0xdd, 0xc2, 0x8b, 0x6e, 0x6c, 0xf7, 0x42, 0x0, 0x18, 0x30, 0xf9, 0xee, 0x94, 0x32, 0xdb, 0xe7, 0xca, 0xba, 0xa7, 0x1, 0xda, 0x3f, 0xb7, 0x78, 0x25, 0xef, 0x26, 0x98, 0x38, 0x42, 0x24, 0xb9, 0x34, 0xa9, 0x7b, 0x36, 0xdc, 0x3d, 0xf5, 0x82, 0x24, 0xd3, 0xad, 0x5c, 0x8, 0x9c, 0xbc, 0x70, 0xf, 0xeb, 0x66, 0x2f, 0xb3, 0xd9, 0xe6, 0x19, 0xf0, 0xc7, 0x5b, 0x4f, 0x14, 0xc8, 0x69, 0x57, 0x25, 0xd2, 0x2c, 0x67, 0x15, 0xb, 0xc7, 0x29, 0xf2, 0xe5, 0xf7, 0xa7, 0x46, 0xe1, 0x59, 0x19, 0xe1, 0x79, 0xd2, 0x3a, 0x5b, 0x61, 0x9c, 0xdb, 0x68, 0x52, 0x5f, 0x5f, 0xbf, 0x70, 0x72, 0x87, 0xb9, 0x52, 0x7, 0x30, 0x70, 0xf2, 0xcf, 0xbb, 0xb9, 0x2d, 0xdb, 0x97, 0x41, 0xb6, 0x2f, 0xc0, 0x3d, 0x2, 0xe7, 0x64, 0x32, 0xf0, 0x48, 0xe, 0x44, 0xa4, 0x52, 0xe, 0xe6, 0xc5, 0x78, 0x88, 0x14, 0x72, 0x25, 0x89, 0xa0, 0x59, 0xed, 0xa4, 0x1a, 0x3f, 0xb7, 0x6e, 0xe1, 0x94, 0xb7, 0xc2, 0x2f, 0x47, 0x5e, 0xb3, 0x94, 0x3b, 0xdf, 0x7b, 0xc5, 0xd0, 0x69, 0xa0, 0xcd, 0x6c, 0x27, 0x4d, 0x9a, 0x0, 0xdd, 0x75, 0xb, 0x2e, 0x70, 0xcb, 0xd5, 0xa1, 0x2a, 0x2e, 0x1d, 0x34, 0xf9, 0xe7, 0x7b, 0x58, 0xb7, 0xe5, 0xdb, 0x36, 0xdb, 0xf2, 0x75, 0x2, 0x26, 0x34, 0xf0, 0x33, 0x69, 0x57, 0xae, 0x70, 0x97, 0xf, 0x8f, 0xf8, 0x2, 0x0, 0x63, 0xcc, 0x66, 0xa6, 0x1a, 0xc7, 0xae, 0x5b, 0x30, 0x39, 0x51, 0x7, 0x89, 0x6a, 0x60, 0xc0, 0xa4, 0x79, 0xd7, 0xd9, 0x6c, 0xf3, 0x37, 0x0, 0xed, 0xcb, 0xb0, 0x47, 0x50, 0x72, 0x26, 0xab, 0x80, 0xe9, 0x41, 0x93, 0x7a, 0x7e, 0xc3, 0xdd, 0x53, 0x8f, 0x1f, 0x34, 0xe5, 0xee, 0x46, 0x9b, 0x6d, 0xa6, 0x71, 0x1a, 0x9a, 0x24, 0xb7, 0x2f, 0xa4, 0x8f, 0x9, 0xea, 0x49, 0xa0, 0x87, 0xa4, 0x3, 0x69, 0x9c, 0x17, 0x20, 0xf7, 0xf9, 0x75, 0xb, 0x2f, 0xca, 0x94, 0x4a, 0xbc, 0xea, 0xc2, 0xd, 0xbc, 0x70, 0x61, 0x83, 0x6c, 0xf6, 0xdf, 0xe5, 0xb6, 0x7c, 0x13, 0x64, 0xb0, 0x20, 0x23, 0xbf, 0xd8, 0x22, 0x49, 0x8, 0x98, 0x4a, 0x82, 0xa4, 0xac, 0x71, 0x52, 0xcf, 0x3b, 0xd, 0xdd, 0xce, 0x5e, 0x33, 0xef, 0xbc, 0xf, 0x92, 0xcf, 0xac, 0x5a, 0x7c, 0x2c, 0x18, 0x63, 0xb3, 0xbb, 0xe6, 0xc9, 0xda, 0x83, 0x3d, 0x43, 0x17, 0x3, 0x49, 0xbe, 0xf6, 0x6, 0x91, 0x5f, 0xdc, 0x2, 0x1, 0xbb, 0x48, 0xf3, 0x1a, 0xa4, 0xde, 0x80, 0x7a, 0x2, 0x28, 0xd2, 0x81, 0x82, 0x7b, 0xae, 0x34, 0xa9, 0xc6, 0xeb, 0xd6, 0x2d, 0x9c, 0xfc, 0x54, 0xa9, 0xa4, 0xab, 0xf6, 0x9, 0x5c, 0xb7, 0xe0, 0x82, 0x16, 0xa7, 0xb1, 0xfb, 0x7f, 0x99, 0x54, 0xe3, 0x75, 0x4, 0xb2, 0x8, 0x69, 0x33, 0x89, 0x9b, 0x45, 0x7c, 0x24, 0x90, 0xcc, 0x1a, 0x27, 0xfd, 0xf0, 0xfa, 0xbb, 0x2e, 0x19, 0x53, 0x4f, 0xc4, 0xf7, 0xf0, 0x71, 0xe1, 0xd3, 0x26, 0xd5, 0x78, 0xa, 0xe9, 0x6c, 0x40, 0x41, 0xd9, 0x6b, 0x77, 0x6d, 0x43, 0xe1, 0x6f, 0x23, 0x64, 0xf, 0x3, 0xb4, 0x17, 0x8a, 0xde, 0x15, 0xde, 0x6b, 0x88, 0xa0, 0x7f, 0x29, 0x57, 0xee, 0x9a, 0x9c, 0x42, 0xd7, 0xdc, 0x3e, 0x3e, 0xeb, 0x34, 0x74, 0x9f, 0x69, 0x52, 0x4d, 0x53, 0x4, 0xbe, 0xdf, 0x76, 0x8b, 0x60, 0x18, 0x4a, 0x85, 0x31, 0xc7, 0xd6, 0x5e, 0xbf, 0x9f, 0x7a, 0x72, 0xfd, 0x5d, 0x17, 0x9f, 0x95, 0x18, 0xd5, 0x12, 0x86, 0x75, 0xb, 0x26, 0xff, 0xc9, 0x34, 0x34, 0x9d, 0x49, 0xe3, 0x2c, 0xf7, 0x2d, 0x8e, 0xfe, 0xf0, 0x15, 0x26, 0x63, 0x31, 0x59, 0x4b, 0x85, 0x79, 0xcf, 0x7e, 0x7, 0x2b, 0xd2, 0xc8, 0xf3, 0x31, 0xd, 0x2e, 0x8a, 0x34, 0xc1, 0xd4, 0x51, 0x51, 0x47, 0x6c, 0xc, 0x81, 0x4f, 0x7e, 0xea, 0xc2, 0x87, 0x4a, 0xf6, 0x3e, 0x35, 0x7b, 0x5, 0xaf, 0xbe, 0xfd, 0x9c, 0x2c, 0x53, 0xd, 0xf7, 0x93, 0xdc, 0x51, 0x64, 0xa, 0x29, 0x1, 0x51, 0xcc, 0x50, 0x18, 0x26, 0xbf, 0x1f, 0x83, 0xe7, 0x2b, 0x0, 0xe3, 0xa4, 0x9f, 0x6c, 0x49, 0xf7, 0x3a, 0xbd, 0xdd, 0xa8, 0x97, 0x10, 0xac, 0x9b, 0x7f, 0xc1, 0x2b, 0x26, 0xd5, 0x38, 0x85, 0xc6, 0x59, 0x82, 0xfc, 0xec, 0x28, 0xa2, 0x99, 0x1c, 0x65, 0xc2, 0xf2, 0xcf, 0xcc, 0xdb, 0xa9, 0xc3, 0xef, 0x99, 0x7f, 0x95, 0x8b, 0x27, 0x4f, 0x39, 0x12, 0xac, 0xcd, 0x9e, 0xd7, 0x9d, 0x1f, 0x4e, 0x2c, 0x55, 0xde, 0x44, 0xdc, 0xc2, 0x6d, 0x36, 0xd3, 0xf, 0x40, 0xda, 0xa3, 0x17, 0x13, 0x71, 0xe7, 0x26, 0xd, 0x5, 0x58, 0x6f, 0x4a, 0x3c, 0xfd, 0xa8, 0x93, 0x6e, 0x1a, 0xff, 0xf2, 0xbc, 0xd3, 0x77, 0x8b, 0xcd, 0x98, 0xd6, 0xce, 0xbf, 0x60, 0x23, 0x4c, 0x6a, 0x16, 0xe9, 0xbc, 0xec, 0x4d, 0x31, 0x18, 0xc9, 0x53, 0x97, 0x6a, 0xc6, 0x4b, 0x1b, 0x2e, 0x6, 0xb3, 0x6d, 0x90, 0xfa, 0xca, 0xaa, 0x7f, 0xfb, 0x33, 0x80, 0x9b, 0x99, 0x1, 0x70, 0xdf, 0x9a, 0x13, 0x2a, 0x4, 0x1, 0x34, 0x34, 0xce, 0x5a, 0x9a, 0xf4, 0xd, 0x6b, 0xe6, 0x9d, 0xf7, 0x61, 0x7b, 0x11, 0xac, 0x3d, 0x60, 0xfd, 0xc2, 0xc9, 0xf7, 0xc0, 0xa4, 0x6e, 0x7, 0xb9, 0xcd, 0xb7, 0x57, 0x75, 0x98, 0xd1, 0x2c, 0xbc, 0x48, 0x56, 0x50, 0x8f, 0x52, 0x71, 0x6b, 0x66, 0x80, 0x23, 0xa7, 0xdc, 0xb5, 0x17, 0x60, 0x87, 0x92, 0x48, 0xe5, 0xf5, 0xde, 0x44, 0xc4, 0x1e, 0x92, 0xdc, 0x42, 0x93, 0x5a, 0xb0, 0x76, 0xfe, 0xa4, 0xc7, 0x3a, 0xa, 0x79, 0x49, 0x82, 0x31, 0xce, 0x2c, 0x9a, 0xd4, 0xbd, 0xbe, 0x8d, 0x3a, 0x98, 0x25, 0x69, 0xf7, 0x19, 0xc5, 0x80, 0xf8, 0xbe, 0xf6, 0x7c, 0xe4, 0xc0, 0xc9, 0xb, 0x87, 0xc4, 0x96, 0xb1, 0x96, 0xa, 0x1e, 0x7d, 0xed, 0xef, 0x8, 0x72, 0x38, 0x80, 0xb4, 0x97, 0xa1, 0xd7, 0xcd, 0xd5, 0xd2, 0x83, 0xf9, 0x5, 0xf7, 0x2a, 0xe0, 0xa4, 0x1e, 0x0, 0x4d, 0xe2, 0xf6, 0xef, 0x8e, 0x82, 0xb5, 0xf3, 0x27, 0x6d, 0x31, 0x4e, 0xfa, 0x36, 0x18, 0x67, 0x29, 0xfc, 0x3e, 0xd9, 0x9f, 0xe9, 0xab, 0xc, 0x27, 0x11, 0xf7, 0x88, 0x9, 0xf7, 0x47, 0x1, 0xff, 0x3f, 0x1, 0x6b, 0x4f, 0x80, 0x74, 0x76, 0x5c, 0x19, 0x6b, 0x62, 0x80, 0x6d, 0xff, 0xd8, 0x48, 0xeb, 0x66, 0xcf, 0x25, 0x4d, 0xca, 0x2f, 0x51, 0xcd, 0xeb, 0x79, 0x7c, 0x75, 0x9f, 0xa0, 0x79, 0x15, 0x30, 0xf7, 0xaf, 0x9b, 0x3f, 0xa9, 0xa2, 0xdd, 0xbf, 0xea, 0xd, 0xd6, 0xde, 0x79, 0xfe, 0xb, 0x34, 0xa9, 0xc5, 0x0, 0x0, 0x1a, 0x11, 0xac, 0x58, 0x31, 0x64, 0xc4, 0x3d, 0x63, 0xc2, 0x8b, 0xf0, 0x28, 0x92, 0xd, 0x24, 0xfa, 0xc6, 0x95, 0xaf, 0x26, 0x6, 0x58, 0x7f, 0xd7, 0xc5, 0x56, 0x6e, 0x76, 0x2c, 0xa0, 0x34, 0x69, 0xc2, 0x5b, 0xaf, 0x54, 0x7e, 0x91, 0x81, 0xe4, 0xef, 0xf5, 0x22, 0xc6, 0x59, 0x44, 0x63, 0x1e, 0xef, 0x6c, 0x2, 0x26, 0x1, 0xa4, 0x59, 0x4c, 0x93, 0x7a, 0x12, 0xfe, 0x7e, 0x46, 0x28, 0x35, 0xc, 0xb0, 0xb6, 0x6, 0x54, 0x98, 0x16, 0x82, 0x6e, 0xb5, 0xf1, 0xd3, 0xe3, 0xe7, 0x46, 0xd2, 0xba, 0x26, 0x6, 0x18, 0x74, 0xd1, 0x3d, 0x7d, 0x41, 0xf4, 0xf6, 0xc4, 0x76, 0x28, 0xa7, 0xf2, 0x56, 0x39, 0xec, 0xfb, 0x92, 0x3f, 0x49, 0xf3, 0x16, 0x8d, 0xf3, 0xd4, 0xda, 0x3b, 0xcf, 0xdf, 0xde, 0xd9, 0xc4, 0x4b, 0x2, 0xd6, 0xde, 0x79, 0xfe, 0x5a, 0x3a, 0xa9, 0xf9, 0x5e, 0x25, 0x73, 0xe, 0x1f, 0x25, 0xc4, 0x9f, 0xda, 0x2f, 0xcf, 0xaf, 0xc4, 0x50, 0x9e, 0xf5, 0xb4, 0x67, 0x63, 0xb7, 0x1e, 0x7, 0x46, 0x95, 0xad, 0x6a, 0x6, 0x18, 0x7c, 0xc9, 0xfd, 0x29, 0x59, 0x3b, 0xa, 0xa0, 0x4d, 0xa2, 0xe4, 0x81, 0x1, 0x3, 0x20, 0x68, 0x9c, 0xf9, 0x34, 0xce, 0x8a, 0xce, 0x26, 0x5c, 0xa2, 0x40, 0xf3, 0x57, 0xd2, 0xbc, 0x8b, 0x76, 0x76, 0x9f, 0xb, 0x5c, 0xe2, 0xfc, 0x1d, 0x67, 0xe0, 0x73, 0xc3, 0xc1, 0x10, 0x3e, 0x1d, 0x55, 0xac, 0xaa, 0x19, 0x60, 0xf5, 0x6d, 0x67, 0x67, 0x9, 0x7d, 0x26, 0x34, 0xd3, 0x55, 0x93, 0x9a, 0xc3, 0xdc, 0x46, 0x4e, 0x0, 0x4d, 0x6a, 0xd9, 0x9a, 0x3b, 0x26, 0xee, 0xd6, 0x63, 0x7f, 0x31, 0x18, 0x63, 0xd6, 0x9b, 0x54, 0xc3, 0x6c, 0xff, 0x51, 0x91, 0x5b, 0x91, 0xd7, 0x0, 0x85, 0x3e, 0x9, 0x9e, 0x22, 0xe8, 0xd, 0xa5, 0xe6, 0x15, 0x3a, 0xa9, 0xfb, 0x49, 0xf3, 0x46, 0xd4, 0x77, 0x6d, 0xf6, 0x8, 0x1a, 0x74, 0xd1, 0xdd, 0x4d, 0xa4, 0xb3, 0xbf, 0xac, 0xed, 0x2b, 0xe8, 0x40, 0x2, 0x7b, 0x43, 0xee, 0x98, 0xdc, 0x86, 0x8d, 0xc9, 0xa8, 0xb9, 0x24, 0xb9, 0x9, 0xe0, 0xa6, 0x24, 0x91, 0x53, 0xf, 0xb0, 0xfa, 0xf6, 0x9, 0x9b, 0x7, 0x7f, 0x71, 0xd1, 0x43, 0x0, 0xfe, 0x3, 0x0, 0x61, 0x12, 0x30, 0xc1, 0x84, 0x26, 0x80, 0x48, 0x12, 0xb2, 0xca, 0xeb, 0x1, 0x7c, 0x97, 0xc6, 0x79, 0x96, 0x74, 0x16, 0x64, 0x65, 0x16, 0x6f, 0xb8, 0x73, 0x42, 0x36, 0x2a, 0x89, 0x58, 0x6, 0x18, 0x74, 0xd1, 0xbd, 0x3d, 0x21, 0x1d, 0xe, 0xe8, 0x40, 0x90, 0x7b, 0x41, 0xea, 0x25, 0x65, 0x8f, 0x90, 0x75, 0x8f, 0x83, 0xf4, 0xe9, 0x60, 0xe1, 0x7a, 0x68, 0x51, 0x67, 0xad, 0x1e, 0x31, 0x9e, 0x3b, 0x21, 0x53, 0x33, 0x4, 0xac, 0x69, 0x2f, 0x42, 0x74, 0x26, 0x8, 0xb0, 0xa0, 0x79, 0x1f, 0xd2, 0x3e, 0x9, 0x35, 0x97, 0xc0, 0x21, 0xc7, 0x73, 0x8e, 0x1, 0x29, 0x70, 0x33, 0xc9, 0x55, 0x34, 0xa9, 0x87, 0x8c, 0x93, 0x9a, 0xbf, 0xfa, 0xf6, 0xf1, 0x9b, 0x4b, 0x25, 0x11, 0xc9, 0x0, 0x83, 0xbf, 0xb8, 0x68, 0x7f, 0x2b, 0xf7, 0x7c, 0x59, 0x77, 0x3a, 0x64, 0xf, 0x2f, 0xcc, 0x33, 0xa7, 0xb0, 0x7b, 0x4e, 0xa, 0xf0, 0xf9, 0xad, 0xb6, 0x1e, 0x20, 0x67, 0x2c, 0x37, 0x8e, 0xf3, 0xfc, 0x9a, 0x3b, 0x26, 0x6e, 0x4b, 0x8, 0xe7, 0x75, 0x5, 0x92, 0xb6, 0x3, 0xf8, 0x33, 0x80, 0x91, 0x40, 0xa2, 0xdb, 0xd7, 0x51, 0xe0, 0x3f, 0xe8, 0x38, 0xaf, 0x11, 0xe6, 0x41, 0x90, 0x3f, 0x5d, 0x3b, 0xef, 0xdc, 0x36, 0x9, 0xd0, 0x31, 0x3d, 0x80, 0xc6, 0xcb, 0x75, 0xbf, 0x5, 0xe8, 0x63, 0x60, 0xd8, 0xf1, 0xb3, 0xc0, 0x41, 0x23, 0x34, 0x3f, 0xd1, 0x26, 0xb7, 0xed, 0x92, 0x15, 0xc8, 0xff, 0x7c, 0x74, 0xd7, 0x86, 0x93, 0x7c, 0x1b, 0x26, 0xf5, 0x88, 0x6c, 0x76, 0x24, 0x22, 0x5d, 0xca, 0x83, 0xa0, 0x72, 0x4b, 0x90, 0x82, 0x77, 0xca, 0xe1, 0x8d, 0x4e, 0xfa, 0x47, 0xae, 0xab, 0x19, 0x1b, 0x16, 0x9c, 0x57, 0xd6, 0xb, 0x28, 0xc, 0x91, 0x3, 0x91, 0x80, 0x5e, 0x0, 0x1a, 0xbc, 0x42, 0x7b, 0x53, 0x8f, 0x79, 0xe9, 0xd2, 0x14, 0x49, 0xb1, 0x40, 0xe9, 0xe7, 0x8a, 0x6c, 0x1, 0xbb, 0x4, 0x54, 0x54, 0x81, 0xdd, 0x9, 0xd6, 0xdc, 0x31, 0xe1, 0x7d, 0x1a, 0xe7, 0x49, 0x1f, 0x47, 0x11, 0xb6, 0x80, 0x0, 0x8a, 0x9f, 0x11, 0xf3, 0x2e, 0xf7, 0xed, 0x7, 0x80, 0xb9, 0xad, 0x52, 0xe2, 0x3, 0x31, 0x3d, 0x80, 0x64, 0xf, 0x0, 0xb0, 0x97, 0x37, 0xbf, 0xac, 0xfc, 0xc6, 0x36, 0xde, 0x5b, 0x54, 0xd6, 0x73, 0xb5, 0x69, 0x95, 0x6c, 0xb0, 0x2e, 0xe7, 0x1d, 0x82, 0x1d, 0xee, 0xdb, 0xd7, 0x91, 0x40, 0xf2, 0x3d, 0x1f, 0xaf, 0x3e, 0x46, 0x8b, 0x5b, 0x7d, 0x2e, 0x66, 0x4c, 0xa, 0xa1, 0xb5, 0x29, 0xc1, 0xa2, 0x8, 0xc3, 0xb4, 0xe3, 0x38, 0x4d, 0xd5, 0x94, 0x27, 0x7a, 0x8, 0x10, 0x7a, 0xe6, 0xed, 0xcb, 0xc5, 0x63, 0x55, 0xa5, 0x3d, 0x74, 0xb9, 0xf8, 0x61, 0x2c, 0xf0, 0x75, 0x10, 0x89, 0xbb, 0x73, 0xd7, 0x15, 0xd0, 0x8, 0x84, 0x65, 0x68, 0x51, 0x4d, 0x8, 0xf, 0x6d, 0x49, 0x20, 0x7f, 0x97, 0x1f, 0x2d, 0x53, 0x81, 0x3c, 0x56, 0x29, 0x44, 0x32, 0x0, 0x8d, 0x69, 0x90, 0x6b, 0xbd, 0x1d, 0x2c, 0x3b, 0x60, 0x1a, 0x33, 0xe7, 0xf2, 0x47, 0xf3, 0x6, 0xc0, 0x8f, 0x34, 0x3, 0x10, 0x70, 0x9, 0xbe, 0x2f, 0x69, 0xbf, 0x4, 0x51, 0x9b, 0xaa, 0x56, 0x9c, 0x4c, 0x68, 0x9f, 0xc0, 0x72, 0xe3, 0x15, 0x4b, 0xbe, 0xf3, 0x1a, 0x3, 0x41, 0xf2, 0x4d, 0x48, 0x1f, 0x69, 0x6, 0x10, 0xe0, 0xa, 0xfc, 0xb0, 0xd0, 0xc1, 0x27, 0x6a, 0xfc, 0x8f, 0xc3, 0x1d, 0xc3, 0x69, 0xe5, 0xce, 0x2f, 0xaa, 0xd6, 0x1b, 0x37, 0x46, 0xb, 0xc8, 0xa9, 0x7a, 0x68, 0xd5, 0xfb, 0xc7, 0xa, 0xf8, 0x8c, 0x7e, 0x9f, 0xb, 0x63, 0xc9, 0xef, 0xe5, 0x2f, 0xa2, 0xfb, 0xe8, 0xea, 0x0, 0x7e, 0x3d, 0x73, 0xf5, 0x67, 0xcc, 0x6f, 0x14, 0xc4, 0x31, 0x41, 0x58, 0xbe, 0xaa, 0xe, 0x71, 0xd1, 0x43, 0x0, 0x0, 0x5, 0xd4, 0x8a, 0xcc, 0x3b, 0x1c, 0xa8, 0x88, 0xf7, 0x25, 0xca, 0xcf, 0xf0, 0x4d, 0x78, 0x55, 0x2c, 0x1, 0xe0, 0x0, 0xd0, 0x54, 0x25, 0xcc, 0xec, 0x2e, 0x40, 0xd2, 0x11, 0xb0, 0x77, 0x69, 0x7a, 0x85, 0x9, 0x1c, 0x77, 0xf, 0xd0, 0x3f, 0x5b, 0x43, 0x82, 0x6b, 0xad, 0xad, 0xca, 0xb4, 0x1c, 0xad, 0x5, 0x0, 0x2d, 0x79, 0xcb, 0x5e, 0x39, 0x83, 0x45, 0x2d, 0x4d, 0xb6, 0x90, 0x91, 0x8, 0xf4, 0x21, 0xf9, 0x91, 0x67, 0x0, 0x92, 0xfb, 0xb4, 0x6d, 0xb9, 0x0, 0xdb, 0x78, 0xaf, 0x6c, 0xb5, 0x64, 0x88, 0x1e, 0x2, 0xc8, 0xf, 0x19, 0xd8, 0xaa, 0xb, 0x8e, 0xef, 0x8, 0xfa, 0xe8, 0xfc, 0x26, 0x56, 0x5e, 0x9c, 0x10, 0x8f, 0x94, 0xdd, 0x46, 0xa5, 0x88, 0x9f, 0x7c, 0x63, 0xa6, 0x9f, 0xcf, 0x81, 0x0, 0x1a, 0x13, 0xc1, 0x74, 0xdd, 0x82, 0xf2, 0x7b, 0xa9, 0x28, 0x68, 0x5f, 0xc5, 0x50, 0xac, 0x71, 0x17, 0xf5, 0x94, 0x2c, 0x5a, 0x73, 0xe, 0x66, 0x43, 0x1b, 0x74, 0x55, 0x4, 0x91, 0x42, 0x20, 0x61, 0xde, 0x20, 0xb8, 0x85, 0xe1, 0x15, 0x27, 0x40, 0x91, 0x5c, 0x10, 0xb2, 0x7, 0x15, 0xcb, 0x9, 0xa5, 0x64, 0xc2, 0xe2, 0x97, 0x21, 0x9b, 0xa2, 0xa4, 0x8f, 0xeb, 0x23, 0xcf, 0x0, 0xec, 0x5, 0x20, 0xd8, 0x53, 0x0, 0x28, 0x25, 0xf4, 0x15, 0xc, 0x97, 0x21, 0x9c, 0x7, 0x32, 0x9a, 0x2f, 0x48, 0x12, 0xcc, 0x0, 0xa8, 0xea, 0xd0, 0xa9, 0x18, 0x4b, 0xa0, 0xde, 0x2, 0xd9, 0x82, 0x60, 0xc1, 0x81, 0xc7, 0xb6, 0x8, 0x76, 0x44, 0x60, 0x3b, 0xfc, 0xf9, 0x5a, 0x40, 0x13, 0xeb, 0x68, 0x3, 0xeb, 0xa4, 0x61, 0xf0, 0xd4, 0x5f, 0xed, 0x6b, 0xad, 0x7b, 0x8a, 0x8f, 0x57, 0x26, 0x85, 0x3b, 0x49, 0x7b, 0x3, 0xfa, 0xe6, 0xe0, 0x8b, 0x7f, 0x51, 0xb1, 0x56, 0x17, 0xed, 0x26, 0xe4, 0xa4, 0x1e, 0x4, 0x9d, 0x6f, 0xd3, 0x38, 0xcf, 0x6, 0x3e, 0x5a, 0xde, 0xaf, 0xaf, 0xaf, 0x3, 0x40, 0xfe, 0x8, 0xc7, 0x3c, 0x37, 0x16, 0x34, 0xee, 0x98, 0x6e, 0x20, 0x1c, 0x3f, 0xb0, 0x68, 0x41, 0xa2, 0x31, 0x5, 0x61, 0x1f, 0x45, 0x20, 0x4d, 0x2f, 0x40, 0xa7, 0xe5, 0x10, 0x17, 0x65, 0xd5, 0xcd, 0xbd, 0x63, 0x99, 0x9e, 0x34, 0x7f, 0x43, 0x43, 0xc8, 0xba, 0x97, 0x3, 0x7c, 0x7a, 0xf0, 0x25, 0xf7, 0xfd, 0xf7, 0xe0, 0xa9, 0xf, 0xec, 0xdd, 0xe6, 0x32, 0xc5, 0xbd, 0x18, 0x3c, 0xf5, 0x57, 0xdd, 0x1, 0xf6, 0x85, 0xec, 0x41, 0x20, 0x7a, 0x43, 0x38, 0x4, 0xd0, 0x27, 0x25, 0x7b, 0x24, 0x81, 0x81, 0xf0, 0xe7, 0xa, 0x80, 0xf0, 0x36, 0xaf, 0x35, 0x51, 0xcf, 0x3f, 0xf, 0x32, 0xf5, 0x75, 0xe3, 0xa4, 0x6f, 0x5c, 0x75, 0xf3, 0xbf, 0xb6, 0xf9, 0x4, 0xae, 0xdd, 0x5, 0x86, 0x5c, 0xfa, 0xc0, 0x30, 0x9b, 0x6d, 0xf9, 0xd, 0x80, 0xbd, 0x93, 0x30, 0x2, 0x85, 0xf6, 0xc7, 0x9, 0x6f, 0xba, 0xb9, 0x85, 0x34, 0x2b, 0x5, 0x3e, 0x44, 0x63, 0xee, 0x5c, 0x7d, 0xeb, 0x59, 0x25, 0xf, 0x9f, 0x6a, 0x73, 0x29, 0x86, 0x5d, 0xfe, 0x70, 0xf, 0x6b, 0xdd, 0x7d, 0x65, 0xed, 0x1, 0x34, 0x66, 0x7f, 0x59, 0xdb, 0xb, 0x72, 0xaf, 0x96, 0x6c, 0xff, 0xd6, 0x66, 0xcd, 0x1a, 0x2a, 0x44, 0xbe, 0xe9, 0x38, 0xd, 0x13, 0x56, 0xdd, 0x32, 0xf6, 0x85, 0x24, 0xd2, 0xac, 0x27, 0x18, 0x3c, 0xf5, 0x57, 0x23, 0xe5, 0x66, 0x5e, 0xf4, 0x77, 0x15, 0x49, 0x62, 0x15, 0x7d, 0xab, 0xa3, 0x66, 0x82, 0xd3, 0xc7, 0x4, 0x6c, 0x26, 0xcd, 0xb, 0x34, 0xce, 0x42, 0xc7, 0x98, 0xfb, 0x56, 0xde, 0x3c, 0x36, 0x72, 0x99, 0x78, 0x9b, 0x3d, 0x82, 0x56, 0xce, 0x3d, 0x63, 0x2b, 0xbc, 0x7d, 0x74, 0x5e, 0xb, 0x55, 0x68, 0x20, 0x2d, 0xfa, 0x79, 0x25, 0x49, 0x64, 0xd3, 0x2c, 0x1, 0xe8, 0x63, 0xa5, 0x83, 0x6a, 0xc5, 0x4c, 0xbd, 0xc1, 0xd0, 0xcb, 0x16, 0xef, 0x67, 0x6d, 0x76, 0x9c, 0x3f, 0xcc, 0x55, 0x61, 0x62, 0x8f, 0xd4, 0xc6, 0xb, 0xf4, 0xe8, 0xd0, 0xbe, 0x8c, 0x22, 0xb0, 0x2f, 0xa0, 0x33, 0x61, 0xdd, 0xc1, 0x2e, 0x30, 0x74, 0xf0, 0xd4, 0x7, 0x17, 0xac, 0xbe, 0x75, 0xec, 0xba, 0xe2, 0x4, 0xaa, 0x6e, 0xb9, 0xc3, 0xa6, 0x3f, 0x96, 0x32, 0x34, 0xbf, 0xf7, 0x48, 0xef, 0x2f, 0x45, 0xaa, 0x68, 0xf6, 0x37, 0x34, 0xce, 0xf9, 0xaa, 0x65, 0xde, 0xb1, 0x44, 0x9f, 0x19, 0x7a, 0xd9, 0x83, 0xfb, 0x77, 0x14, 0x71, 0x3a, 0x6, 0x34, 0x0, 0xd6, 0x9d, 0xee, 0xf, 0x94, 0x2c, 0xa8, 0x7b, 0x9b, 0xfc, 0x44, 0x59, 0x6, 0x87, 0x41, 0xfb, 0xcb, 0x9d, 0x5b, 0x24, 0x6f, 0x22, 0x4f, 0x9f, 0x80, 0xec, 0x38, 0x52, 0x7d, 0xa2, 0x4a, 0x55, 0x35, 0x3, 0xac, 0x9c, 0xf3, 0xf9, 0xac, 0x80, 0x17, 0xe0, 0x9f, 0xa3, 0x5a, 0x9d, 0xdc, 0x9f, 0x2f, 0xb7, 0xa7, 0x6d, 0x4, 0x9a, 0x86, 0xbd, 0x40, 0xc2, 0x88, 0xce, 0x26, 0x59, 0x92, 0x20, 0xd9, 0x43, 0x1, 0xec, 0x7, 0x50, 0x85, 0xcb, 0x3b, 0xc2, 0x78, 0xa8, 0x1c, 0x87, 0x28, 0xfe, 0xb6, 0x50, 0xbb, 0xa0, 0xdf, 0xad, 0xbe, 0x4a, 0xe3, 0x6c, 0x8c, 0x2a, 0x57, 0x4d, 0x63, 0xf7, 0x1f, 0x6e, 0x19, 0xfb, 0x2a, 0x8d, 0x79, 0x33, 0x98, 0x32, 0x8e, 0x76, 0x74, 0x8d, 0x9a, 0xf4, 0x88, 0xb3, 0x6d, 0x53, 0x0, 0x5, 0xe9, 0xe3, 0xb2, 0xf6, 0xe4, 0x21, 0x97, 0x2d, 0xee, 0xd9, 0xb9, 0x64, 0x4b, 0x6, 0x6, 0x5f, 0xfa, 0xe0, 0x60, 0x59, 0x4d, 0xf6, 0x55, 0xdd, 0xdc, 0x36, 0x37, 0x49, 0x40, 0xac, 0xd7, 0x40, 0xce, 0x96, 0xf, 0x10, 0xdc, 0xd2, 0xd0, 0xfd, 0x63, 0xaf, 0x47, 0xc5, 0xab, 0x89, 0x1, 0x6, 0x5f, 0x72, 0x9f, 0x1, 0xcc, 0x3, 0x2, 0x32, 0x2, 0x90, 0x53, 0xe5, 0xa, 0x2e, 0x14, 0x75, 0x61, 0xc5, 0x5d, 0x5f, 0x41, 0x78, 0x9e, 0x71, 0xa1, 0xf1, 0xb2, 0xf6, 0xd4, 0xc4, 0xa9, 0xd1, 0x9, 0x40, 0xe0, 0xc, 0xc0, 0x8e, 0xf1, 0x1c, 0xab, 0x0, 0x76, 0xc0, 0x89, 0x68, 0x34, 0x39, 0x5f, 0x3e, 0x90, 0x66, 0x57, 0xf1, 0x9, 0xa6, 0x1, 0xd4, 0xc4, 0x0, 0xd, 0x3d, 0x7a, 0xb, 0x34, 0xf7, 0x4a, 0xc8, 0xfa, 0x54, 0x8c, 0x98, 0x19, 0x2a, 0x35, 0x25, 0x5c, 0x1c, 0xb7, 0x60, 0x37, 0xb0, 0x83, 0x49, 0x9d, 0x3d, 0xe4, 0xd2, 0x87, 0x7a, 0x77, 0x36, 0x1, 0x6b, 0x81, 0x21, 0x97, 0x3e, 0x74, 0x2, 0x64, 0xc7, 0xe6, 0x25, 0xff, 0xf0, 0xa, 0xea, 0xb6, 0xe0, 0xaa, 0x54, 0x58, 0xdc, 0xb7, 0x61, 0x13, 0x2d, 0x77, 0xd1, 0x98, 0x57, 0xe2, 0xca, 0x57, 0x13, 0x3, 0x2c, 0xfb, 0xe9, 0xb1, 0xa2, 0x71, 0x56, 0x80, 0x39, 0x37, 0x2e, 0x86, 0x57, 0xf8, 0xb4, 0x86, 0x52, 0x52, 0x8e, 0xf7, 0x3e, 0xef, 0x2e, 0x45, 0x48, 0x1a, 0x7, 0xe0, 0x92, 0x76, 0xa0, 0x4b, 0x87, 0xc0, 0xb0, 0x69, 0x8f, 0xf4, 0x4, 0xf4, 0x45, 0x49, 0x47, 0x7b, 0x92, 0xbf, 0x9, 0x26, 0x4f, 0x22, 0xf0, 0x11, 0x87, 0xab, 0x52, 0x61, 0xb1, 0xd, 0xcb, 0x77, 0x15, 0x20, 0x40, 0x2e, 0x91, 0x70, 0x7f, 0x5c, 0x19, 0x6b, 0xd6, 0xdf, 0x57, 0xcd, 0x3d, 0x7d, 0xab, 0x31, 0xce, 0x8b, 0x20, 0x4b, 0xc, 0x3, 0x95, 0x76, 0x5f, 0x26, 0x30, 0x3e, 0x76, 0x87, 0xec, 0x85, 0x43, 0x2e, 0x7d, 0x68, 0x6c, 0x47, 0x10, 0x2c, 0x69, 0x90, 0xb5, 0x57, 0x49, 0xf6, 0xdc, 0xd0, 0xce, 0x1d, 0x55, 0xe2, 0x4, 0x95, 0xc6, 0xb, 0xe5, 0x65, 0x56, 0xff, 0xe1, 0x96, 0x33, 0x63, 0xd7, 0x59, 0x24, 0x62, 0xc0, 0x31, 0x4e, 0xea, 0x1a, 0x0, 0x9b, 0xdb, 0xd2, 0xc9, 0xc7, 0x89, 0x7f, 0x45, 0xcf, 0x7e, 0x55, 0x68, 0x25, 0xdb, 0x1f, 0xd0, 0x15, 0xc3, 0xa7, 0x3f, 0xba, 0x17, 0x76, 0x23, 0x18, 0x7a, 0xf9, 0xc3, 0x17, 0xc9, 0xba, 0x97, 0x90, 0xec, 0xe6, 0x1f, 0x22, 0xdb, 0xca, 0x15, 0x24, 0xa, 0x3f, 0xa5, 0xde, 0xb0, 0x8d, 0xf1, 0x82, 0x85, 0x96, 0xfe, 0x53, 0xc9, 0x35, 0x16, 0xc9, 0x30, 0x80, 0x49, 0xfd, 0x15, 0x60, 0x16, 0x2c, 0xa7, 0xb4, 0xb4, 0x56, 0x78, 0xe2, 0x9e, 0x7d, 0x7f, 0x44, 0x43, 0x1a, 0x40, 0xfa, 0xbc, 0xeb, 0x66, 0xef, 0x4e, 0x88, 0x36, 0xed, 0xe, 0xc3, 0xa6, 0x3d, 0x72, 0x34, 0x64, 0xaf, 0x4, 0xd1, 0x97, 0x9e, 0xda, 0xc7, 0xb0, 0x7a, 0x86, 0x12, 0xf8, 0x29, 0x3b, 0x61, 0x56, 0x3e, 0x9e, 0x48, 0xe3, 0xef, 0x4b, 0x65, 0x5e, 0x26, 0xcd, 0xba, 0x52, 0x65, 0xad, 0x99, 0x1, 0x86, 0x5f, 0xf1, 0x44, 0xca, 0x75, 0x33, 0x17, 0x93, 0xdc, 0xb3, 0x60, 0x82, 0xa3, 0xc6, 0x8b, 0x86, 0x14, 0x4, 0x1a, 0x7a, 0x9b, 0x2b, 0xc9, 0x9e, 0x36, 0xf4, 0xf2, 0xc5, 0x8b, 0x3b, 0x9b, 0xb8, 0xe5, 0x60, 0xd8, 0xb4, 0x47, 0x87, 0x59, 0xd7, 0x9d, 0x2b, 0xd9, 0x91, 0xb9, 0x63, 0x71, 0x88, 0xa, 0x8d, 0x64, 0x85, 0x97, 0x2, 0xa5, 0x2e, 0x3e, 0x9d, 0x70, 0x78, 0x4e, 0x93, 0x22, 0x9d, 0x7b, 0xff, 0x70, 0xf3, 0xbf, 0xfe, 0xb2, 0x54, 0x79, 0x6b, 0x62, 0x80, 0x61, 0x57, 0x3c, 0x9e, 0x92, 0xcd, 0x5c, 0x27, 0xeb, 0xde, 0x0, 0xa0, 0x67, 0xc1, 0x92, 0xe4, 0x4, 0x2e, 0x7f, 0xdf, 0x3b, 0xfa, 0x27, 0x8c, 0xc1, 0xba, 0xf6, 0xb3, 0x43, 0x2e, 0x5b, 0x7c, 0x7f, 0x65, 0xa5, 0xec, 0x38, 0x18, 0x7a, 0xf9, 0xa3, 0x43, 0x25, 0xf7, 0x2e, 0x40, 0x47, 0xfa, 0x36, 0xd, 0x86, 0x7e, 0x6b, 0xc1, 0x3, 0xbd, 0x65, 0xfe, 0x8, 0x7e, 0xc3, 0x57, 0xee, 0x14, 0x94, 0xf0, 0x5, 0xc0, 0xa5, 0xe1, 0xdf, 0xca, 0x95, 0xb9, 0x6a, 0x6, 0x18, 0x7a, 0xf9, 0xa3, 0xd, 0x72, 0x33, 0xdf, 0xb3, 0xae, 0xfb, 0xdf, 0x0, 0xd3, 0x5e, 0x68, 0xb4, 0x64, 0x5f, 0x9d, 0x2a, 0xd3, 0x3a, 0xdc, 0x18, 0xa6, 0x21, 0x9d, 0x39, 0xe4, 0xd2, 0x87, 0x7e, 0x3b, 0xf4, 0xf2, 0x47, 0x92, 0xde, 0x95, 0xac, 0x26, 0x18, 0x36, 0xed, 0xb1, 0x93, 0xad, 0xcd, 0x3c, 0x28, 0xab, 0xc3, 0xa, 0xd7, 0x52, 0x94, 0xd2, 0x7a, 0xe2, 0x70, 0x81, 0xd6, 0x71, 0xf3, 0x9a, 0xdd, 0x2e, 0x92, 0x1b, 0x40, 0xf3, 0xa6, 0x84, 0x5d, 0xa, 0xb6, 0x53, 0x4, 0x43, 0x62, 0x86, 0x27, 0xfc, 0x9, 0x6c, 0x75, 0x68, 0x67, 0x31, 0x54, 0xc5, 0x0, 0xc3, 0xaf, 0x78, 0xbc, 0x1b, 0xa0, 0x1f, 0x59, 0x6b, 0xaf, 0x3, 0xe1, 0xd0, 0x10, 0xc1, 0x21, 0xc7, 0x85, 0x2b, 0xc7, 0xa2, 0x18, 0x9f, 0x45, 0xe1, 0xcc, 0x8b, 0x2b, 0x5, 0x78, 0x8, 0xb8, 0x9f, 0xa1, 0x74, 0x9, 0x10, 0x46, 0xd0, 0xd1, 0xd6, 0xba, 0x2f, 0xf, 0xb9, 0xfc, 0x91, 0xe3, 0x3a, 0x8c, 0xc2, 0x25, 0x60, 0xc8, 0x65, 0xf, 0xff, 0xa7, 0xb5, 0xd9, 0x45, 0x24, 0xf, 0xa, 0xd4, 0x6f, 0x1a, 0xe3, 0xf9, 0x39, 0x17, 0x8a, 0x3f, 0x85, 0xf5, 0x46, 0xc, 0x2e, 0xa, 0xf1, 0x26, 0x3f, 0x2e, 0x7d, 0x7c, 0xac, 0x5c, 0x75, 0xf3, 0x99, 0x3, 0x8d, 0x93, 0xfe, 0x94, 0x49, 0x35, 0xee, 0x63, 0x52, 0x4d, 0x4d, 0x26, 0x95, 0xee, 0x63, 0x9c, 0xf4, 0x20, 0x3a, 0xe9, 0xd1, 0x74, 0xd2, 0x67, 0xd1, 0x38, 0x5f, 0xa6, 0x71, 0xbe, 0x44, 0xf0, 0xd9, 0x72, 0x65, 0x2f, 0x27, 0xb8, 0x47, 0x10, 0xff, 0xd7, 0x7b, 0xca, 0xda, 0xaf, 0x4a, 0xf6, 0x3b, 0x8, 0x56, 0xa3, 0xb0, 0xd2, 0x95, 0xae, 0x55, 0x2d, 0x8c, 0xf5, 0xd8, 0x5b, 0x62, 0xc8, 0xb9, 0x70, 0x2b, 0x68, 0x1e, 0x4b, 0x77, 0xdb, 0xe7, 0xbc, 0x17, 0x67, 0x1c, 0xd3, 0xe1, 0x9b, 0x48, 0xe, 0xbf, 0xe2, 0x89, 0x46, 0xeb, 0x66, 0xd6, 0xca, 0xba, 0x7, 0x91, 0xdc, 0x23, 0x98, 0x92, 0x87, 0xc4, 0x44, 0x71, 0x12, 0x78, 0xe8, 0x92, 0xab, 0x40, 0xe7, 0xe4, 0x95, 0x73, 0x3e, 0xf7, 0x7e, 0x71, 0x94, 0xa3, 0xbe, 0xf2, 0x5b, 0xb6, 0x6c, 0x7b, 0x97, 0x4e, 0xba, 0x81, 0xb2, 0xd6, 0x48, 0xd6, 0x5d, 0x35, 0xf7, 0x8c, 0xb2, 0x47, 0xcc, 0x54, 0x44, 0x85, 0xa1, 0xd3, 0x1e, 0xed, 0xe, 0x60, 0x32, 0xac, 0x9d, 0x5, 0xf8, 0x67, 0xff, 0xa1, 0xe3, 0xf, 0x8c, 0x40, 0xe1, 0x3c, 0x78, 0xb, 0xc8, 0xb7, 0x4, 0xde, 0xea, 0x66, 0xb3, 0xd7, 0xaf, 0xb9, 0xf5, 0xcc, 0x4c, 0xd, 0x59, 0xb4, 0x9, 0x86, 0x5c, 0xfe, 0x48, 0x9a, 0xc0, 0x22, 0x12, 0x47, 0xc9, 0xda, 0xdc, 0x2c, 0x1b, 0x2b, 0x26, 0x7a, 0x25, 0x55, 0x46, 0x56, 0xe0, 0x5d, 0xab, 0xe6, 0x9e, 0x3e, 0x25, 0xc9, 0xba, 0x54, 0x54, 0xd8, 0x61, 0xd3, 0x1e, 0x3b, 0x49, 0x72, 0x7f, 0xe3, 0x89, 0xb5, 0x1e, 0x9b, 0xb7, 0x4a, 0x2d, 0xee, 0xec, 0x87, 0x70, 0xcc, 0xb8, 0xc5, 0x23, 0x2c, 0x8a, 0xab, 0xc8, 0x38, 0x91, 0xa7, 0x83, 0x49, 0xda, 0x4a, 0x9a, 0xd7, 0x40, 0x2e, 0x2, 0xcc, 0x4f, 0x56, 0xce, 0xf9, 0x6c, 0xe2, 0x1e, 0x45, 0xc3, 0xaf, 0x78, 0x7c, 0xa8, 0xb5, 0xee, 0xb5, 0xde, 0xde, 0x48, 0x3a, 0x88, 0xa4, 0xbf, 0x3f, 0x62, 0x20, 0xaa, 0x7b, 0xc7, 0x27, 0xb6, 0xaa, 0x53, 0xb8, 0x2e, 0x51, 0x38, 0x2a, 0xf6, 0xa4, 0x2e, 0xc4, 0x97, 0xbf, 0xf, 0x3, 0x9f, 0x4d, 0x35, 0x34, 0x7d, 0x6e, 0xd9, 0xcf, 0x4e, 0x4a, 0xf4, 0xc8, 0x98, 0x8a, 0xe, 0x8d, 0x12, 0xf0, 0x16, 0xc0, 0x55, 0x20, 0x86, 0x12, 0x85, 0x47, 0xb7, 0x14, 0x54, 0xa8, 0x18, 0xca, 0x59, 0x7f, 0xc2, 0x61, 0x2c, 0xfb, 0x5d, 0x1e, 0xb5, 0xb9, 0x19, 0x70, 0x89, 0x64, 0xf, 0xc9, 0xe, 0x84, 0x78, 0x10, 0xa9, 0xb, 0x87, 0x4e, 0x7b, 0x74, 0x29, 0xc0, 0xc5, 0x0, 0x9f, 0x58, 0x75, 0xd3, 0xe7, 0x3e, 0xac, 0x16, 0x41, 0x43, 0xa7, 0x3d, 0x76, 0x24, 0x81, 0x33, 0x41, 0x9c, 0x62, 0xdd, 0xec, 0x27, 0x1, 0xf4, 0x26, 0xd1, 0xe4, 0x17, 0x26, 0xe7, 0xa, 0x17, 0xb9, 0x8c, 0x92, 0x6d, 0xb8, 0x8f, 0x7f, 0xe, 0xed, 0xba, 0xc2, 0xd7, 0x68, 0xcc, 0x6d, 0x49, 0x13, 0x3f, 0x8e, 0x14, 0x25, 0x61, 0xd8, 0xf4, 0x5f, 0x9f, 0x2e, 0xeb, 0x3e, 0xc, 0x44, 0xad, 0x70, 0xed, 0x70, 0x28, 0x68, 0x57, 0xa1, 0x1d, 0x4b, 0x20, 0xa9, 0x19, 0xe4, 0x3f, 0x0, 0xbc, 0xb, 0xe0, 0x6d, 0x80, 0x7f, 0x34, 0xc6, 0xbc, 0x28, 0x61, 0x83, 0x64, 0x37, 0x1b, 0x63, 0xb6, 0x9, 0xcc, 0x2, 0x70, 0x8d, 0x31, 0x8e, 0x9b, 0xcd, 0x34, 0x2, 0xec, 0x66, 0xc, 0xf, 0x4, 0x74, 0x8c, 0xb5, 0x3a, 0xe, 0xd0, 0x1, 0x0, 0x7a, 0xc8, 0xda, 0xde, 0x24, 0xf7, 0xcb, 0x21, 0x2d, 0x7c, 0x42, 0xa, 0xa, 0xfb, 0xe9, 0x44, 0x2a, 0x15, 0x4a, 0x4f, 0x92, 0x5, 0xcd, 0x8d, 0x3d, 0xf7, 0xeb, 0x73, 0xd5, 0x33, 0xd7, 0xf, 0x4e, 0x5c, 0xce, 0xa9, 0xf8, 0xec, 0x60, 0x9, 0x2b, 0x40, 0xf3, 0x2, 0xa0, 0xe3, 0x2, 0x4f, 0x9e, 0xf0, 0x69, 0xd1, 0xed, 0xf, 0x5, 0x63, 0x49, 0xee, 0xc1, 0x3b, 0x69, 0x3b, 0x68, 0x3a, 0x10, 0xd, 0x1b, 0x25, 0x1c, 0x2, 0xe0, 0x10, 0x3f, 0xc6, 0x9, 0x92, 0x1d, 0x27, 0xe1, 0x7d, 0x48, 0xcd, 0x90, 0xcd, 0x10, 0xb4, 0x0, 0xe4, 0x66, 0xb2, 0x24, 0xe9, 0x0, 0x4a, 0x59, 0xab, 0xee, 0x80, 0xf6, 0x7, 0x90, 0xf3, 0x48, 0xa, 0x16, 0xc9, 0xf8, 0xe, 0xd1, 0x2c, 0x76, 0xe7, 0xab, 0x9c, 0xf8, 0xc5, 0xe3, 0x40, 0x1, 0x7e, 0x45, 0x43, 0x4a, 0xb0, 0x0, 0xc, 0x69, 0x9e, 0x14, 0xf9, 0x83, 0xf6, 0x20, 0x3e, 0x50, 0x5, 0x3, 0x90, 0x7c, 0x17, 0xe4, 0x77, 0x64, 0xdd, 0x27, 0xdb, 0xeb, 0xb8, 0xb4, 0xa, 0x4a, 0x13, 0x2a, 0x57, 0x48, 0x81, 0x24, 0xc2, 0x4e, 0x97, 0xc1, 0x88, 0xda, 0x1d, 0x40, 0x5f, 0x40, 0x7d, 0xc1, 0x9c, 0x4a, 0x91, 0x4b, 0x26, 0x70, 0x79, 0xf, 0x8c, 0x6e, 0xc8, 0x7f, 0x9b, 0xcb, 0x28, 0xbf, 0x59, 0x46, 0xb2, 0x65, 0x2f, 0xc4, 0x6f, 0xee, 0x5c, 0x24, 0x43, 0x72, 0x9, 0x8d, 0xf3, 0x5f, 0x2b, 0x67, 0x9f, 0x5a, 0xd6, 0xa0, 0x53, 0x2d, 0x54, 0xdc, 0x85, 0xaf, 0x9c, 0xf3, 0x59, 0x57, 0x56, 0xcf, 0x1, 0xe6, 0x7, 0xcc, 0x4f, 0x3b, 0x29, 0xce, 0xae, 0xf, 0xc4, 0xdb, 0xb2, 0x11, 0x11, 0x16, 0xf5, 0x1e, 0x31, 0xdf, 0x44, 0x7d, 0xe7, 0x3f, 0x33, 0x58, 0x72, 0xe, 0x7f, 0x5b, 0x4e, 0x7f, 0x7e, 0x1, 0x86, 0x6, 0x86, 0x26, 0xbf, 0xb6, 0xda, 0xf, 0xf3, 0xe6, 0x1c, 0x20, 0xd2, 0x0, 0xfe, 0x7d, 0xb1, 0x52, 0x5e, 0x6c, 0xcf, 0x47, 0x4c, 0x19, 0x4b, 0xc5, 0x61, 0x89, 0xfa, 0x86, 0x5d, 0xb9, 0xe8, 0x19, 0x73, 0x1e, 0x58, 0x31, 0xfb, 0xd4, 0x76, 0xf5, 0x8e, 0xae, 0x6a, 0xc, 0x5f, 0x75, 0xd3, 0xe7, 0x32, 0xc6, 0x71, 0x66, 0xd0, 0x98, 0x3f, 0x7a, 0x1e, 0x81, 0xf0, 0x14, 0x83, 0xbc, 0xcd, 0x1a, 0xa0, 0x77, 0x94, 0x27, 0x3, 0x79, 0x3d, 0xf8, 0xf1, 0xc3, 0xe4, 0x1b, 0x11, 0x7c, 0xbb, 0x49, 0x7e, 0x4d, 0x8, 0xb, 0xc3, 0xa, 0xec, 0x61, 0x21, 0x3b, 0x49, 0x2e, 0x6e, 0x48, 0x78, 0x6c, 0x65, 0x53, 0x2a, 0x8e, 0x1b, 0x32, 0x52, 0x79, 0xc6, 0x2b, 0x22, 0xbc, 0xcd, 0xa1, 0x77, 0xa, 0x8b, 0x1f, 0x25, 0x7c, 0x5f, 0x9c, 0x6f, 0x51, 0x18, 0x23, 0xca, 0x15, 0x67, 0xe3, 0x29, 0x28, 0x77, 0x44, 0x1d, 0xa, 0x3b, 0x6, 0x56, 0xdc, 0x43, 0x77, 0x8, 0x3, 0x0, 0xc0, 0x8a, 0xd9, 0xa7, 0xbc, 0x9, 0x98, 0x6f, 0x48, 0xb0, 0xc1, 0x4a, 0x97, 0x90, 0xcd, 0x3a, 0xa8, 0x72, 0x40, 0x71, 0xff, 0x40, 0x54, 0x13, 0xd8, 0xaa, 0x3d, 0xd3, 0x5e, 0xb0, 0xb5, 0x1d, 0x22, 0x30, 0x57, 0x80, 0xc5, 0x8, 0xec, 0xc6, 0xc5, 0x47, 0x1b, 0xe2, 0x17, 0x7f, 0xc7, 0x32, 0xf9, 0x97, 0xcb, 0xaf, 0x5c, 0x1e, 0x95, 0x94, 0xc5, 0xbb, 0xf7, 0x27, 0xc0, 0x34, 0x61, 0xd8, 0x15, 0x4f, 0x8c, 0xa9, 0x4b, 0x6, 0x0, 0x80, 0x15, 0x37, 0x9e, 0xf2, 0x2b, 0x81, 0x73, 0xfd, 0x59, 0x89, 0xe0, 0xbc, 0xdb, 0x9c, 0xdf, 0xa3, 0x1f, 0x6, 0x1, 0xaf, 0xd0, 0x38, 0xf3, 0x40, 0xf3, 0x3d, 0x90, 0x8f, 0xa3, 0x50, 0x4b, 0x66, 0x72, 0x3e, 0x92, 0x9d, 0x24, 0x8a, 0x24, 0x8, 0x61, 0x1c, 0x2, 0x1a, 0xe, 0x60, 0xca, 0x51, 0x57, 0x3d, 0x9d, 0x6e, 0xaf, 0xfc, 0x6a, 0x56, 0xe3, 0x68, 0x9c, 0xaf, 0xd2, 0x38, 0xbf, 0x1, 0xe8, 0x2, 0xc, 0x66, 0xa5, 0x8, 0xf0, 0x3, 0x81, 0x4f, 0x1, 0x9c, 0x4d, 0x9a, 0xff, 0x30, 0xc6, 0x4c, 0x5f, 0x31, 0xfb, 0x94, 0x6f, 0x3, 0xe6, 0x6b, 0xa0, 0xf9, 0x6d, 0x28, 0xae, 0xef, 0x27, 0x17, 0xb5, 0x6d, 0x5a, 0xa5, 0x17, 0x6a, 0xfc, 0xbe, 0xf3, 0x2f, 0x7f, 0xd2, 0x43, 0x79, 0xbc, 0x68, 0x8c, 0x9b, 0x75, 0xcf, 0x6b, 0x2f, 0x6, 0x48, 0xa4, 0xc9, 0x8c, 0xb8, 0xf2, 0xa9, 0x23, 0x24, 0xfb, 0x6b, 0x49, 0x69, 0x49, 0x1b, 0xc, 0xb9, 0x95, 0xc6, 0xac, 0x0, 0x78, 0xf3, 0xf2, 0x59, 0x27, 0xbd, 0x19, 0x11, 0xff, 0x13, 0xd6, 0xba, 0xf3, 0x25, 0x9d, 0x60, 0x72, 0xaa, 0x5b, 0xe8, 0xa0, 0xe4, 0x92, 0xc5, 0x6d, 0x4b, 0x6f, 0xd1, 0xd6, 0x78, 0x51, 0x71, 0xc3, 0xcf, 0x95, 0xa4, 0x53, 0xd, 0x4, 0x55, 0x8d, 0xcd, 0x43, 0x5e, 0x2f, 0xca, 0x47, 0x68, 0xcc, 0xf8, 0x95, 0xb3, 0x4f, 0x2e, 0x77, 0xa, 0x7a, 0xd5, 0x25, 0xa8, 0x19, 0x46, 0x5c, 0xf9, 0xd4, 0xf5, 0x92, 0x5e, 0x7, 0x39, 0x6f, 0xc5, 0xac, 0x93, 0xca, 0x6e, 0xf5, 0x3a, 0xfc, 0x4b, 0x4f, 0x35, 0x42, 0xf6, 0x69, 0x41, 0xc7, 0x78, 0x2, 0x1e, 0x73, 0x15, 0x66, 0x58, 0xa7, 0x8b, 0x41, 0x51, 0x78, 0xc, 0x29, 0x45, 0x22, 0x96, 0xf9, 0xbe, 0x38, 0x4e, 0x71, 0xfc, 0x28, 0x4, 0x29, 0x26, 0x8d, 0xf6, 0x60, 0x15, 0x7f, 0x78, 0x7c, 0x97, 0x34, 0x3f, 0x58, 0x31, 0xfb, 0xe4, 0x1f, 0x26, 0x9d, 0x7e, 0xa7, 0xe, 0x9a, 0x23, 0xaf, 0x59, 0x4a, 0xb7, 0x65, 0xfb, 0xe3, 0x24, 0x8e, 0x6, 0xd0, 0xc3, 0xdb, 0x3c, 0x23, 0xd8, 0x87, 0x24, 0x8a, 0x5, 0x18, 0xf1, 0x5c, 0xe9, 0xe4, 0x43, 0x5c, 0xba, 0xa5, 0x58, 0x24, 0xa, 0x65, 0xc5, 0xdf, 0x95, 0xcb, 0x2f, 0xae, 0x4c, 0x8c, 0xf9, 0x46, 0xc1, 0x7a, 0x4b, 0xff, 0xe0, 0x68, 0x3e, 0x63, 0x85, 0xcf, 0xaf, 0xba, 0xf1, 0x94, 0x44, 0xcd, 0xc1, 0x9d, 0x6a, 0xca, 0x5d, 0xf6, 0xd3, 0x63, 0xb5, 0xf2, 0xc6, 0x53, 0x4f, 0x25, 0x53, 0xb7, 0x4a, 0x7c, 0xc3, 0x57, 0xd5, 0x19, 0xbd, 0xce, 0x90, 0x31, 0xcf, 0x61, 0x4d, 0xa1, 0x54, 0xdc, 0x8, 0xbd, 0x32, 0x36, 0x9d, 0xb8, 0x30, 0x96, 0xf8, 0xae, 0x5c, 0x7e, 0x71, 0x71, 0xe2, 0xbe, 0xf1, 0xe4, 0xe3, 0x90, 0x6e, 0x3b, 0x84, 0xe4, 0xb7, 0x92, 0xa6, 0x41, 0x67, 0xdb, 0xf2, 0x1, 0x0, 0xcb, 0x67, 0x8d, 0xb9, 0x16, 0x34, 0xd7, 0x4a, 0x58, 0xf, 0xef, 0x4, 0x92, 0x28, 0x4a, 0xed, 0x56, 0x57, 0xb0, 0xb7, 0x72, 0xb9, 0xb0, 0x52, 0xdf, 0x6, 0x2e, 0x71, 0x7e, 0xf8, 0x36, 0x0, 0x1f, 0x24, 0x8d, 0xfb, 0xba, 0xd2, 0x9b, 0x86, 0x7f, 0xe9, 0xe9, 0xde, 0xa0, 0x1e, 0x25, 0x30, 0x24, 0x5f, 0xbc, 0xb8, 0x3d, 0x74, 0x6b, 0x19, 0x71, 0x4b, 0xa5, 0xd1, 0x16, 0xa9, 0x22, 0x4e, 0x7a, 0xc8, 0x7d, 0x17, 0xac, 0x95, 0xf4, 0x67, 0x2d, 0x73, 0x5d, 0x9b, 0xef, 0xc9, 0x62, 0x5b, 0x4f, 0xa5, 0x7, 0xdd, 0xbe, 0xb7, 0x4b, 0x46, 0xfe, 0x5b, 0x0, 0x92, 0x5e, 0x27, 0xf9, 0xff, 0x56, 0xcc, 0x3e, 0x69, 0x66, 0xd2, 0x38, 0x6f, 0x77, 0x4b, 0x53, 0x25, 0x60, 0xc, 0xcf, 0x12, 0xb0, 0x7f, 0xa1, 0x46, 0x10, 0xc7, 0xa3, 0x49, 0xf0, 0x6e, 0xb5, 0x69, 0xb3, 0xd5, 0x73, 0x89, 0x19, 0x41, 0x17, 0x40, 0xd6, 0x6f, 0xdc, 0x8d, 0x3e, 0x81, 0x63, 0x36, 0x88, 0x28, 0xdc, 0x37, 0xc0, 0x8f, 0xf3, 0xf, 0xc7, 0x38, 0xd7, 0x2f, 0xfb, 0xd9, 0x89, 0xb3, 0xd1, 0xe, 0x50, 0x17, 0x43, 0x40, 0x0, 0x56, 0x9a, 0x2, 0xb0, 0x4f, 0xcc, 0xa0, 0x19, 0x46, 0x54, 0x95, 0x57, 0xf8, 0xfb, 0xa8, 0xb4, 0xa2, 0xde, 0x17, 0x43, 0x41, 0x9a, 0xf2, 0xaf, 0x90, 0x15, 0x34, 0x6c, 0x14, 0x33, 0x24, 0xcd, 0x12, 0x63, 0x9c, 0x13, 0x49, 0x73, 0xa9, 0xf2, 0x7b, 0x39, 0xd2, 0x5b, 0xff, 0x58, 0xd0, 0xe5, 0xe7, 0xbc, 0x87, 0x83, 0xd6, 0xef, 0xf9, 0xf4, 0xf3, 0xb2, 0xf6, 0x22, 0x3e, 0x50, 0x6f, 0x3d, 0x0, 0xb9, 0xb7, 0x7f, 0xab, 0xe8, 0xa6, 0x5f, 0x6b, 0xab, 0x2f, 0x47, 0xe4, 0x36, 0x30, 0x41, 0x99, 0x11, 0x42, 0xc1, 0xc6, 0xf7, 0xc4, 0x12, 0x49, 0xff, 0x43, 0xf2, 0xe9, 0x65, 0x33, 0x47, 0x67, 0x0, 0xfc, 0x6e, 0xe4, 0x55, 0xcf, 0xbe, 0x2d, 0x6b, 0x7f, 0x9, 0x61, 0xcf, 0x12, 0xbe, 0x23, 0x16, 0xa0, 0x1, 0xf9, 0x24, 0xc9, 0x6f, 0x2e, 0x9b, 0x39, 0x7a, 0x59, 0x72, 0x18, 0x6e, 0xd, 0x75, 0xd3, 0x3, 0xc, 0xbf, 0xf2, 0x99, 0x43, 0xad, 0xd4, 0xd8, 0x7a, 0x7d, 0x21, 0x4a, 0x48, 0xe2, 0x40, 0xbc, 0x74, 0x8f, 0x98, 0x6f, 0xa3, 0x24, 0x7d, 0xc4, 0xe4, 0x17, 0x91, 0x6, 0x10, 0x78, 0xfb, 0x22, 0x98, 0xb4, 0xb, 0xc9, 0x76, 0xa4, 0x31, 0xf, 0xd2, 0x38, 0xa3, 0x40, 0xf3, 0x79, 0x3a, 0xd, 0x4f, 0x2c, 0xff, 0xd9, 0x89, 0x39, 0x1f, 0xc5, 0x65, 0x33, 0x47, 0x3f, 0xe, 0x9a, 0xa1, 0x2, 0x7e, 0xed, 0x37, 0x79, 0x81, 0x94, 0x37, 0xc9, 0xc8, 0x60, 0x1, 0x89, 0x1, 0x79, 0x9b, 0x80, 0x69, 0xed, 0x4d, 0x7c, 0xa0, 0x9e, 0x7a, 0x0, 0xa2, 0x1f, 0xc1, 0xc6, 0xdc, 0x53, 0x4e, 0xb2, 0x2a, 0xd7, 0x52, 0x5b, 0x79, 0xd0, 0xf8, 0xdd, 0x27, 0x83, 0x77, 0x88, 0x77, 0x57, 0x60, 0x44, 0x7a, 0xe5, 0x7b, 0x89, 0xfc, 0x9c, 0x7d, 0xe0, 0xe, 0x61, 0xfe, 0xa, 0x70, 0x11, 0xa8, 0x5b, 0x1, 0xbc, 0xe, 0x68, 0xe7, 0xf2, 0x99, 0xa3, 0x23, 0x3d, 0x72, 0x97, 0xff, 0x6c, 0xf4, 0x9f, 0x47, 0x5c, 0xf5, 0xec, 0x64, 0x8, 0x93, 0x24, 0x3b, 0x23, 0xa8, 0x82, 0xef, 0xdc, 0x42, 0x80, 0x5f, 0x3, 0x79, 0xc7, 0x8a, 0x99, 0x27, 0xbc, 0xd7, 0x11, 0x68, 0xaf, 0x1f, 0x6, 0x0, 0x8e, 0x5, 0xd8, 0xc3, 0xf7, 0xc9, 0xa8, 0xc8, 0xc9, 0xc4, 0x9f, 0x7d, 0xa, 0x3c, 0x68, 0x2, 0x46, 0x0, 0x80, 0xd0, 0x92, 0x6c, 0x0, 0x21, 0x71, 0xbd, 0x48, 0x66, 0xab, 0xc6, 0x9b, 0x97, 0x0, 0xb2, 0x20, 0x7, 0x81, 0xdc, 0x22, 0x69, 0xeb, 0xf2, 0x99, 0xa3, 0xdb, 0xe4, 0x88, 0xba, 0x7c, 0xe6, 0xe8, 0x77, 0x46, 0x5e, 0xbd, 0x64, 0x2e, 0xc4, 0xc5, 0x90, 0x9e, 0x5, 0x70, 0xa0, 0xa4, 0x77, 0x40, 0x4e, 0x4, 0xf4, 0xc2, 0xa, 0x6f, 0xc8, 0xe8, 0x10, 0xa8, 0x1b, 0x35, 0x70, 0xf8, 0x97, 0x9f, 0x7d, 0x9e, 0xc4, 0x31, 0xbe, 0x27, 0x47, 0x5b, 0x9, 0x92, 0xd7, 0xbb, 0x3c, 0xcf, 0xd9, 0xdb, 0x1, 0x2c, 0x5, 0x70, 0x32, 0xa0, 0xb3, 0x51, 0x62, 0xdb, 0xd9, 0x90, 0xb7, 0x50, 0x45, 0x6e, 0xed, 0x45, 0xbd, 0x4d, 0x66, 0xf9, 0xcc, 0xd1, 0xd, 0x6d, 0xfa, 0x30, 0x6, 0x46, 0x5e, 0xbd, 0xe4, 0x50, 0x49, 0xc3, 0x0, 0xac, 0x5f, 0x3e, 0xf3, 0x84, 0xd, 0xed, 0x89, 0xe3, 0x48, 0x3c, 0x74, 0x74, 0x86, 0x71, 0x30, 0xe2, 0xaa, 0xe7, 0xde, 0x2, 0xd0, 0x2b, 0xbc, 0xdf, 0x50, 0x29, 0xa2, 0x14, 0xbf, 0x97, 0xf4, 0x17, 0x80, 0x13, 0x1, 0xac, 0xa1, 0x77, 0x9e, 0x71, 0x2f, 0x0, 0x7b, 0x4a, 0x6a, 0x80, 0x77, 0xbc, 0x7d, 0xf, 0x0, 0x9f, 0x2, 0xd4, 0x17, 0xc0, 0xbe, 0x0, 0x3e, 0x9, 0x78, 0x1b, 0x51, 0x55, 0xea, 0xcf, 0x1f, 0xc, 0x33, 0x92, 0x32, 0xa4, 0xe9, 0xb6, 0x7c, 0xe6, 0xf1, 0xd9, 0xb6, 0x7e, 0x1b, 0x5, 0x47, 0x7f, 0x65, 0x69, 0xea, 0xf7, 0x33, 0x8e, 0xad, 0x29, 0x8d, 0x6a, 0xa1, 0x6e, 0x86, 0x0, 0x82, 0x3f, 0x17, 0xf4, 0x15, 0xf9, 0xb, 0xa1, 0x3c, 0xbf, 0x48, 0x8f, 0x28, 0x11, 0x94, 0xf1, 0x37, 0x44, 0xf4, 0x5, 0x32, 0x6f, 0x14, 0xb8, 0xce, 0xcd, 0xba, 0x7f, 0x58, 0x39, 0xfb, 0x44, 0xb, 0x60, 0x93, 0x7f, 0xe5, 0x60, 0xc4, 0xd5, 0x2f, 0x90, 0xb0, 0x3d, 0x0, 0xee, 0x9, 0x8f, 0x21, 0xfa, 0xc8, 0x6a, 0x89, 0x31, 0x74, 0x0, 0x6f, 0x71, 0x65, 0x5, 0x83, 0x8e, 0x7f, 0xca, 0x6d, 0x32, 0xde, 0x81, 0x9d, 0x45, 0x7c, 0xa0, 0x8e, 0x18, 0x40, 0xc0, 0x8f, 0x48, 0xb3, 0x44, 0xb2, 0x97, 0x82, 0x3c, 0x2d, 0x24, 0x4, 0x14, 0xf4, 0xba, 0x7e, 0x80, 0xbf, 0xf, 0x1e, 0x20, 0x6b, 0x9, 0xe0, 0xfb, 0x12, 0x1f, 0xf5, 0x89, 0x1f, 0x9, 0xcb, 0x6f, 0x38, 0x4e, 0x0, 0xb6, 0xf8, 0x17, 0x46, 0x5c, 0xb5, 0xe4, 0x75, 0x92, 0xbf, 0x15, 0x70, 0x1c, 0x80, 0x22, 0x51, 0xa1, 0x75, 0xe1, 0x42, 0x5c, 0xa8, 0xd0, 0x9e, 0x8c, 0xdb, 0xea, 0xa8, 0x13, 0xad, 0xa, 0xea, 0x46, 0xd, 0x5c, 0x3e, 0xf3, 0xf8, 0xd7, 0x97, 0xdd, 0x30, 0xea, 0x3e, 0x80, 0xd7, 0x1, 0xbc, 0x58, 0xc2, 0xaf, 0x3, 0xe7, 0x92, 0x22, 0x87, 0x11, 0x92, 0x46, 0xa1, 0x77, 0xbf, 0x7, 0xf8, 0xbf, 0xcb, 0x67, 0x1e, 0x5f, 0xd1, 0x59, 0x43, 0xc6, 0x18, 0xd2, 0x98, 0xbb, 0x42, 0xf6, 0xf9, 0x78, 0x3b, 0x7d, 0xa1, 0x4b, 0x97, 0x6f, 0xac, 0x81, 0x5, 0xf8, 0x1a, 0xda, 0xd7, 0x61, 0xa0, 0xdd, 0xa1, 0x6e, 0xd9, 0x77, 0xc4, 0x55, 0x4b, 0x8e, 0x4, 0x30, 0x82, 0xe4, 0x89, 0x0, 0xc6, 0x1, 0x8, 0x6f, 0x11, 0x13, 0x8c, 0xc1, 0x9b, 0x1, 0x9c, 0xb5, 0x7c, 0xe6, 0xf1, 0x4b, 0xaa, 0xc9, 0x63, 0xe4, 0xd5, 0x2f, 0x1c, 0x28, 0xd9, 0x4d, 0xfe, 0xb9, 0x88, 0xa5, 0x5c, 0x0, 0xa, 0xc0, 0xd7, 0x30, 0x32, 0x92, 0x16, 0x1, 0x98, 0xbc, 0x7c, 0xe6, 0xf1, 0x65, 0x17, 0x61, 0xd6, 0x2b, 0xd4, 0x2d, 0x3, 0x4, 0x30, 0xe2, 0xea, 0xe7, 0xfb, 0x0, 0x38, 0x3, 0xc0, 0xbf, 0x10, 0x3c, 0xa, 0xc0, 0x18, 0xdf, 0x4a, 0xb0, 0x43, 0xd0, 0x95, 0xcb, 0x6f, 0x18, 0x75, 0x47, 0x8d, 0xe9, 0x3f, 0x65, 0x68, 0x8e, 0x87, 0x77, 0xf6, 0x9e, 0xe7, 0x25, 0x1c, 0xc3, 0xa, 0xb2, 0x5, 0xea, 0xc2, 0x2e, 0x2b, 0xfb, 0x9f, 0x0, 0x7e, 0xb8, 0xfc, 0x86, 0x51, 0x5d, 0xc, 0xd0, 0x11, 0x70, 0xd4, 0x57, 0x96, 0xe, 0x7, 0x30, 0x9, 0x5e, 0x6f, 0xb0, 0xe9, 0xc5, 0x19, 0xc7, 0x7e, 0xb7, 0x96, 0xf4, 0x46, 0x5e, 0xb3, 0x94, 0x92, 0x3d, 0x95, 0xe4, 0xaf, 0x0, 0xec, 0x11, 0xee, 0x5, 0x22, 0xb4, 0x90, 0x9c, 0xfc, 0xe1, 0x3f, 0x5b, 0x0, 0x63, 0x49, 0xf3, 0x48, 0x67, 0x2c, 0x4d, 0x4f, 0xa, 0x76, 0x2b, 0x6, 0x68, 0xf, 0x18, 0x79, 0xcd, 0xd2, 0x3d, 0x24, 0xbd, 0x4c, 0xf2, 0xc0, 0x62, 0xb5, 0x33, 0xce, 0x5b, 0x59, 0xd2, 0x26, 0x92, 0x2f, 0x91, 0xbc, 0xf8, 0xc5, 0x19, 0xc7, 0x6c, 0x6a, 0x4b, 0x3e, 0xf5, 0xa, 0xff, 0xf4, 0xc, 0x0, 0x0, 0x23, 0xaf, 0x7e, 0xe1, 0x7a, 0x1a, 0x5e, 0x7, 0x20, 0xe5, 0xfb, 0x61, 0x65, 0x0, 0xec, 0x82, 0xb0, 0xb, 0xc4, 0xe, 0x0, 0x5b, 0x24, 0x6d, 0x26, 0xb9, 0xd, 0xc2, 0x66, 0x41, 0x4b, 0x8c, 0x31, 0xbf, 0xfb, 0xfd, 0x4f, 0x8e, 0x59, 0x57, 0x63, 0xd6, 0x9d, 0xe, 0x75, 0xa3, 0x6, 0x76, 0x26, 0xd0, 0x98, 0xff, 0x91, 0x74, 0x8, 0x80, 0x1e, 0x24, 0xb7, 0xc0, 0xdb, 0x5b, 0x6f, 0x33, 0xd, 0xdf, 0x3, 0xf0, 0xb6, 0xa4, 0x57, 0x1, 0xbc, 0xf4, 0xe2, 0x8c, 0x63, 0xdf, 0xe9, 0xec, 0xb2, 0x76, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0x74, 0x41, 0x17, 0xd4, 0x6, 0xff, 0x1f, 0x32, 0x68, 0x5, 0x7e, 0x99, 0xd5, 0x97, 0x49, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x80, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc3, 0x3e, 0x61, 0xcb, 0x0, 0x0, 0x19, 0xdb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xec, 0x99, 0x3, 0x94, 0x7b, 0x39, 0x14, 0xc6, 0xd7, 0xb6, 0xed, 0x87, 0x62, 0x6d, 0xdb, 0x33, 0xe5, 0x6b, 0xc7, 0x6b, 0xdb, 0xb6, 0x77, 0x5c, 0xb7, 0x6b, 0xdb, 0xb6, 0x6d, 0xdb, 0xb6, 0xbd, 0xdb, 0x74, 0xbf, 0xde, 0xe6, 0x35, 0xff, 0xe6, 0xcc, 0xdb, 0x1d, 0x9f, 0x37, 0xd3, 0xe4, 0x9c, 0xdf, 0x49, 0x5e, 0x9c, 0x7c, 0x37, 0x37, 0x39, 0xed, 0x54, 0x2a, 0xa8, 0xa0, 0x82, 0xa, 0x2a, 0xa8, 0xa0, 0x82, 0xa, 0x2a, 0xa8, 0xa0, 0x82, 0xa, 0xf5, 0x17, 0x8c, 0x48, 0x6a, 0xe, 0x23, 0xd4, 0x73, 0xa5, 0x16, 0xe8, 0xba, 0x5f, 0xb, 0x74, 0xdf, 0xac, 0x87, 0x7a, 0x2f, 0x34, 0xc3, 0xfd, 0x9d, 0x66, 0x24, 0x71, 0x0, 0xca, 0xa2, 0x66, 0x34, 0xb3, 0xba, 0x37, 0x9e, 0x5f, 0x78, 0x92, 0x2e, 0x5f, 0x5, 0x3d, 0xd4, 0x77, 0xe6, 0x72, 0xd, 0xa7, 0x33, 0x50, 0x2a, 0xa3, 0x35, 0x9c, 0x5e, 0xd4, 0x1a, 0xcf, 0xfc, 0x19, 0x7c, 0xae, 0x35, 0x76, 0xbe, 0xa5, 0x5, 0x3a, 0x9f, 0xd5, 0x1a, 0xbb, 0x1e, 0xd4, 0x83, 0x3d, 0xb7, 0x1b, 0xe1, 0xbe, 0x4b, 0xcd, 0x48, 0xf2, 0x0, 0x4f, 0x2c, 0xe7, 0x9f, 0x4, 0x4b, 0x57, 0xc1, 0x13, 0x3f, 0x6b, 0x16, 0x8, 0xfc, 0xe9, 0x72, 0xd, 0x67, 0x94, 0xb4, 0xc6, 0x32, 0x67, 0x56, 0x41, 0x9e, 0xc, 0x2f, 0xeb, 0xfc, 0xa, 0xc6, 0x70, 0x97, 0xc7, 0xca, 0x2c, 0x3e, 0x8e, 0x53, 0x55, 0xc1, 0xb4, 0xb2, 0x1b, 0xeb, 0x70, 0xcd, 0x38, 0xb1, 0x29, 0x23, 0x92, 0x38, 0x79, 0xa4, 0xfd, 0xad, 0xbe, 0xff, 0x63, 0x53, 0x1b, 0xd1, 0xf4, 0x36, 0x7a, 0xa0, 0xf3, 0x77, 0x12, 0xb6, 0xe1, 0xc, 0x46, 0xb1, 0x94, 0x6, 0xac, 0x36, 0x26, 0x63, 0x28, 0xc2, 0x0, 0x1a, 0xd6, 0x3c, 0xf0, 0x89, 0xa9, 0x95, 0x32, 0x63, 0x18, 0x8c, 0x68, 0x66, 0x29, 0x23, 0x92, 0xdc, 0x5, 0xc2, 0x77, 0xe1, 0x7e, 0x7e, 0xaa, 0x2a, 0x4a, 0xa0, 0xf3, 0xf, 0xe4, 0xef, 0x30, 0x62, 0xf7, 0x1f, 0xec, 0x7d, 0x0, 0xfd, 0xfd, 0x83, 0xfe, 0x4a, 0x2, 0xea, 0xdf, 0x11, 0xee, 0x5, 0x7e, 0xc7, 0x55, 0x70, 0x4, 0xd2, 0xd3, 0x28, 0x95, 0xc6, 0xe6, 0xb4, 0xaf, 0x60, 0x46, 0x53, 0xbb, 0x18, 0xa1, 0xbe, 0xab, 0xb0, 0xd9, 0x3f, 0x83, 0xaa, 0x6b, 0xd6, 0x85, 0x8, 0xdf, 0x98, 0x56, 0x66, 0xbd, 0x61, 0x8f, 0x11, 0xcb, 0x2d, 0x36, 0x45, 0x9f, 0xc, 0x94, 0x6, 0x3, 0x1f, 0xfb, 0x2f, 0x23, 0xdc, 0x7f, 0x99, 0x1e, 0x18, 0x5d, 0x3, 0x50, 0xc2, 0x47, 0xb3, 0xcb, 0x43, 0xf8, 0x3d, 0xe1, 0xe6, 0xef, 0xc4, 0x26, 0x33, 0x50, 0x2, 0xd8, 0xf8, 0xae, 0x32, 0x8c, 0xc7, 0x94, 0xbf, 0x1c, 0x84, 0xc0, 0x9, 0x7e, 0xdc, 0x13, 0xcb, 0xcf, 0x3f, 0xf4, 0x97, 0x7f, 0x72, 0x7a, 0x33, 0x9a, 0xde, 0x1b, 0xfd, 0xd0, 0xe9, 0x47, 0x9f, 0x83, 0x86, 0xe6, 0x14, 0xe8, 0x2a, 0xe2, 0x1d, 0xf0, 0xa2, 0x27, 0x5e, 0x98, 0x56, 0xa9, 0x36, 0xa, 0x1, 0xaf, 0xea, 0xc5, 0x3d, 0xb1, 0x6c, 0xb, 0x4e, 0xfc, 0xdd, 0xd8, 0xdc, 0x12, 0x87, 0x8b, 0xce, 0xd3, 0x41, 0x21, 0x2, 0x44, 0x63, 0x4, 0xd2, 0x30, 0x98, 0x33, 0xe1, 0x9, 0x66, 0x1a, 0xd2, 0x78, 0x10, 0xe, 0x2f, 0xfa, 0x47, 0xf4, 0x60, 0x37, 0x84, 0xa4, 0xfe, 0x2a, 0xfd, 0xcb, 0x4, 0x44, 0x9a, 0x8b, 0xcf, 0xec, 0x34, 0xc6, 0xfe, 0xc1, 0xd7, 0x7a, 0xe1, 0x74, 0x4a, 0xbd, 0x51, 0x8, 0x10, 0x31, 0x3, 0x31, 0x4a, 0x53, 0xc0, 0x0, 0x17, 0x5e, 0xe4, 0xf3, 0x3c, 0x2a, 0xe3, 0x14, 0xc9, 0x8, 0xac, 0xac, 0x5, 0x61, 0x1c, 0xdd, 0xb1, 0xaf, 0xf5, 0xa2, 0xe9, 0x4c, 0x2b, 0x37, 0xbf, 0x27, 0x56, 0x58, 0x6, 0xc6, 0x66, 0x80, 0xd, 0xd1, 0xf6, 0x1f, 0xd1, 0x8f, 0xe8, 0xd3, 0x19, 0x31, 0x3e, 0x28, 0x95, 0xbd, 0x7, 0xfa, 0x55, 0x6, 0x30, 0x1a, 0x1, 0xae, 0xfc, 0xb, 0x3d, 0x20, 0x84, 0x1f, 0x4, 0x4c, 0x8, 0x82, 0x38, 0xd4, 0xfb, 0x11, 0xae, 0x82, 0xd5, 0x21, 0xec, 0xac, 0x38, 0xdd, 0xcb, 0x80, 0x55, 0xbc, 0xf1, 0xc2, 0x9a, 0xde, 0xa6, 0xc2, 0x5a, 0x65, 0xb1, 0xe1, 0x21, 0x3a, 0x60, 0x64, 0xdd, 0x78, 0x4c, 0x5e, 0x8b, 0xbb, 0xfb, 0x1, 0x78, 0x9a, 0x77, 0xe5, 0xbe, 0x6, 0xd, 0x79, 0x25, 0x1a, 0xf7, 0xaf, 0xd1, 0xb8, 0x2, 0x3c, 0x4d, 0xe7, 0xcc, 0xa2, 0x5e, 0xfb, 0xe1, 0xc4, 0xc3, 0xb8, 0x53, 0x8b, 0xa0, 0x4, 0x18, 0xc5, 0x32, 0x21, 0xe9, 0x3b, 0x0, 0xe1, 0x0, 0xd2, 0x24, 0x20, 0xee, 0xf5, 0xcb, 0x71, 0xaf, 0x1f, 0xd, 0x91, 0xef, 0x45, 0xde, 0xaf, 0xbc, 0x9e, 0x83, 0x90, 0x7c, 0x1c, 0xe0, 0x3c, 0x8e, 0x9c, 0xcf, 0xc7, 0x14, 0x75, 0xfe, 0x42, 0x5f, 0x23, 0x7a, 0x4, 0x7a, 0x9b, 0xce, 0x5a, 0x1a, 0xde, 0x6b, 0x6f, 0x18, 0xef, 0xf2, 0x75, 0xfe, 0x6, 0xc8, 0x9e, 0x82, 0x53, 0xf9, 0x43, 0x79, 0x73, 0x8d, 0x50, 0x6f, 0x15, 0x5d, 0x66, 0xa0, 0x7c, 0xb4, 0x41, 0x5c, 0xe4, 0x69, 0x81, 0x28, 0x23, 0xb1, 0x45, 0x1b, 0xa4, 0xed, 0x7c, 0xb9, 0x4c, 0x8c, 0xed, 0x38, 0x9e, 0x21, 0xc6, 0xf9, 0x1b, 0x1e, 0x60, 0x35, 0x33, 0x96, 0x5b, 0xc4, 0xdb, 0x7c, 0xee, 0xec, 0x43, 0x59, 0x2f, 0xea, 0xcf, 0xe2, 0x8d, 0x9f, 0x65, 0xea, 0xe1, 0xbe, 0x77, 0x78, 0xbf, 0x5f, 0x9a, 0xb1, 0xfc, 0x46, 0xde, 0xa6, 0xb3, 0x67, 0xa8, 0x4b, 0x3, 0xc0, 0xe2, 0xb7, 0x81, 0x1, 0x7c, 0x62, 0x88, 0xd, 0x66, 0x94, 0x1e, 0x1c, 0x8c, 0xb7, 0xb1, 0xd3, 0xf2, 0x77, 0x69, 0x94, 0xa9, 0xf1, 0x1e, 0xb8, 0x52, 0xde, 0xc1, 0x15, 0x73, 0x3a, 0xae, 0x1c, 0x1d, 0xcc, 0x8a, 0xbc, 0xff, 0xf4, 0xa, 0x38, 0xed, 0xb, 0xa2, 0xfe, 0xa1, 0x7a, 0x10, 0xfd, 0x10, 0x3d, 0xd5, 0xf9, 0x22, 0xff, 0x8, 0xfc, 0xef, 0x30, 0x5f, 0xfd, 0x79, 0x80, 0xa6, 0xb3, 0x97, 0xc1, 0x46, 0xbe, 0x5b, 0x39, 0x91, 0x10, 0x2d, 0xdc, 0x87, 0x8d, 0x96, 0x8, 0x3b, 0xe0, 0x58, 0x26, 0xb5, 0x1d, 0x29, 0x21, 0x82, 0xe6, 0x27, 0xf2, 0x78, 0x9a, 0x83, 0x77, 0xc6, 0x75, 0xf0, 0xa, 0x1b, 0x7a, 0x5b, 0xce, 0x9b, 0x7d, 0xa0, 0x5f, 0x9, 0x51, 0xa6, 0xe3, 0xaa, 0xba, 0x8f, 0xd7, 0x2f, 0xf2, 0xd8, 0xf6, 0x2c, 0xd4, 0x97, 0xc7, 0xca, 0xe4, 0x51, 0x6f, 0xa9, 0xfa, 0xf3, 0x2, 0x91, 0xe4, 0x6b, 0x7a, 0x79, 0x83, 0xab, 0x9b, 0xda, 0xcf, 0x41, 0xda, 0x19, 0x51, 0x67, 0xbc, 0x9, 0xf5, 0x31, 0xc2, 0x9e, 0x27, 0xd2, 0x95, 0xf9, 0x93, 0x21, 0x3c, 0xf, 0x11, 0x1b, 0xa4, 0xfb, 0x7e, 0x53, 0x94, 0x15, 0x1, 0xd5, 0x95, 0xfb, 0xe1, 0x6b, 0x29, 0x52, 0x1c, 0x49, 0x3d, 0x8c, 0xff, 0x29, 0xd6, 0xad, 0x2f, 0x3, 0x88, 0xa6, 0x1f, 0xe2, 0x1b, 0xc8, 0x45, 0x75, 0x3b, 0x10, 0x8d, 0x10, 0x79, 0x7c, 0xfe, 0x94, 0xaf, 0x93, 0xa0, 0xc9, 0x67, 0x60, 0x8, 0xdb, 0xe2, 0x6a, 0x68, 0xa5, 0xb2, 0x8a, 0xc8, 0x4c, 0xea, 0x8b, 0x11, 0xa2, 0xf, 0x6, 0x60, 0x4, 0x89, 0xf, 0xcc, 0x58, 0xa1, 0xa5, 0x8e, 0x1e, 0x82, 0xf9, 0x5d, 0xe1, 0x1e, 0x3f, 0xb5, 0x4f, 0x13, 0xc5, 0x13, 0x9, 0x31, 0x67, 0x56, 0xf5, 0x8, 0x38, 0xd1, 0xe0, 0x4f, 0x23, 0x9c, 0x0, 0x55, 0x8f, 0xc5, 0x78, 0x2c, 0x90, 0xda, 0x89, 0xba, 0x89, 0x6f, 0x60, 0x3c, 0x7, 0xd4, 0xcb, 0x3b, 0xc0, 0x84, 0x1, 0xbc, 0x42, 0x9b, 0x10, 0x49, 0x4c, 0x48, 0x20, 0x18, 0xab, 0xc4, 0xfd, 0x22, 0x3d, 0xe5, 0x37, 0x21, 0xca, 0x64, 0x50, 0xc6, 0xe4, 0x7e, 0xf4, 0x70, 0xe2, 0x73, 0x3c, 0x92, 0xf, 0x98, 0xec, 0xff, 0xcb, 0xc7, 0x70, 0xef, 0xbd, 0x86, 0x85, 0x17, 0xcb, 0x8b, 0x36, 0xb1, 0xf8, 0x9, 0xe, 0x93, 0xd3, 0xc3, 0xc0, 0xf6, 0x28, 0x48, 0x27, 0x3f, 0x81, 0x27, 0x38, 0x74, 0x92, 0x8a, 0x5f, 0xc8, 0xe0, 0xe4, 0x7f, 0x66, 0x9f, 0x2, 0x2c, 0x96, 0xf1, 0xb8, 0x9e, 0x21, 0x2f, 0x60, 0xef, 0x5, 0xe, 0xc7, 0x77, 0x78, 0x44, 0x9e, 0x30, 0x19, 0xff, 0xef, 0xbf, 0xdf, 0x8c, 0xa4, 0x7e, 0x31, 0xb0, 0x60, 0xc0, 0xc5, 0x47, 0x1c, 0x55, 0x88, 0xfd, 0xc0, 0x61, 0xb0, 0xb2, 0xf7, 0xfb, 0x5b, 0xcf, 0x77, 0xef, 0x8f, 0x44, 0xb0, 0xce, 0x6e, 0xb8, 0xf1, 0x13, 0xf0, 0xb, 0xd7, 0xdc, 0x83, 0xa9, 0xef, 0x6f, 0xbd, 0x60, 0x66, 0x2c, 0xea, 0xc1, 0xaa, 0xf0, 0xd1, 0x54, 0x19, 0x26, 0xd2, 0xa, 0xc0, 0xf7, 0x26, 0xfd, 0x15, 0x7e, 0x21, 0x3c, 0xd8, 0xb5, 0xe2, 0x43, 0xf4, 0xd5, 0x30, 0x49, 0xb8, 0xf0, 0xd4, 0xf, 0x10, 0xf5, 0x21, 0x3c, 0x58, 0x2e, 0x87, 0x31, 0x9c, 0x8c, 0xfc, 0xe5, 0x1c, 0xfe, 0xfc, 0x58, 0x16, 0xf5, 0x1e, 0xe6, 0x8b, 0x23, 0xd0, 0x96, 0x21, 0x6, 0x3, 0x6d, 0x44, 0x5a, 0xa4, 0x1d, 0xcb, 0x44, 0x1d, 0xc7, 0x6f, 0x30, 0xf8, 0xbe, 0xd3, 0x36, 0xe, 0x79, 0xce, 0xed, 0x6, 0x3f, 0x5f, 0xe7, 0x36, 0x6, 0x3f, 0x10, 0xa0, 0x7c, 0xfa, 0x6f, 0x5d, 0xbe, 0xfd, 0xa2, 0x99, 0xdd, 0x29, 0x7e, 0xcb, 0x85, 0xb3, 0xe3, 0xdf, 0xb6, 0x87, 0xb0, 0x80, 0x62, 0xed, 0x42, 0x33, 0x3f, 0x22, 0xff, 0x61, 0x18, 0x42, 0x2, 0x86, 0xd0, 0xe2, 0x6f, 0xbf, 0x68, 0xae, 0x4a, 0xfd, 0xf3, 0x56, 0xc2, 0x82, 0x9e, 0x94, 0x36, 0x85, 0x99, 0x56, 0xba, 0xc4, 0x51, 0x60, 0x3f, 0x80, 0x2d, 0xfe, 0xfb, 0xde, 0xe6, 0x73, 0xda, 0xdc, 0xfc, 0x7a, 0x3f, 0xdb, 0xb6, 0x60, 0x8f, 0x95, 0x61, 0x9c, 0xda, 0x93, 0x62, 0xe5, 0xde, 0x41, 0xbd, 0x2b, 0x40, 0x17, 0x8c, 0xe2, 0xbe, 0x4a, 0xdd, 0x34, 0xd5, 0x3, 0x76, 0x5b, 0x90, 0x16, 0x38, 0x7e, 0x67, 0xfe, 0x87, 0xb4, 0x8c, 0x63, 0x19, 0xcf, 0x77, 0x48, 0x3b, 0xd7, 0x1d, 0xfc, 0x5c, 0x9d, 0xe7, 0x3b, 0xe0, 0xba, 0xb8, 0xf8, 0xbc, 0xe, 0xa3, 0x7d, 0x89, 0x17, 0xce, 0x5d, 0x79, 0xa7, 0xab, 0xa7, 0x73, 0xa5, 0xf8, 0xbe, 0x96, 0xf3, 0x22, 0x34, 0x51, 0x12, 0x31, 0x23, 0x26, 0x2e, 0x16, 0x4e, 0x65, 0x44, 0x94, 0xc7, 0x94, 0x9f, 0x2d, 0xe2, 0xbb, 0xc6, 0x60, 0x14, 0x2, 0x3a, 0xfd, 0xd8, 0x1f, 0x6f, 0xbc, 0xf0, 0xa4, 0xaf, 0xe5, 0xfc, 0xd, 0x5c, 0x29, 0x3e, 0x1e, 0x71, 0x8b, 0xe3, 0x34, 0xbf, 0xc5, 0x5, 0x2d, 0x3, 0xb1, 0x21, 0x66, 0xc, 0x69, 0xe, 0xff, 0xa6, 0x32, 0x29, 0x5f, 0xe4, 0x59, 0x20, 0x36, 0x78, 0x44, 0x9b, 0x11, 0x62, 0x11, 0xa3, 0xd7, 0xc6, 0x12, 0xf1, 0xb0, 0xd6, 0x21, 0xd2, 0xd5, 0x83, 0x2, 0xd7, 0x7f, 0x90, 0x3b, 0x4f, 0x7e, 0xeb, 0x85, 0x33, 0x60, 0x72, 0xbd, 0x74, 0xaa, 0x69, 0xe2, 0x5c, 0x4c, 0x97, 0x62, 0xd6, 0x1a, 0x20, 0xe3, 0x79, 0x55, 0x44, 0x3d, 0xd7, 0xcc, 0x97, 0xf0, 0x36, 0xb9, 0xd0, 0x0, 0xfc, 0xed, 0x17, 0x4f, 0xb, 0xb7, 0xb4, 0x79, 0xed, 0x6, 0xe6, 0xdc, 0x2, 0x89, 0x2d, 0xa5, 0x1, 0xa5, 0x6b, 0x90, 0xda, 0x38, 0xaf, 0x43, 0xb4, 0xa7, 0xf4, 0x78, 0xad, 0x1, 0x94, 0xef, 0xff, 0x47, 0x7c, 0xad, 0x17, 0xac, 0xef, 0x2a, 0x3, 0x58, 0xbe, 0xfd, 0xe2, 0x85, 0xf1, 0x98, 0x7b, 0xca, 0x63, 0xfd, 0xcb, 0xbd, 0x39, 0x0, 0x3b, 0x8f, 0x45, 0x71, 0xbc, 0x9f, 0x6d, 0xd, 0xd6, 0xae, 0xd7, 0xb6, 0xed, 0xdd, 0x87, 0x6a, 0x6d, 0xdb, 0xb6, 0x8d, 0xc7, 0xba, 0xfd, 0xb4, 0xb6, 0x6d, 0xdb, 0xb6, 0xed, 0xde, 0xee, 0x2f, 0xed, 0x49, 0x5e, 0xa6, 0x93, 0x4f, 0x2f, 0x49, 0x1f, 0x32, 0xf3, 0x9f, 0x73, 0x73, 0x93, 0x1e, 0xfe, 0xef, 0xe9, 0x4d, 0xa6, 0xd5, 0x93, 0x73, 0x9d, 0xcd, 0xa4, 0x5c, 0x37, 0xd7, 0x6b, 0x60, 0x7e, 0xef, 0x37, 0xfc, 0xc0, 0x37, 0x5, 0x6a, 0x3f, 0xf7, 0x23, 0x9, 0xfd, 0x0, 0xbc, 0x2, 0x9e, 0xe6, 0xbd, 0xc5, 0xc3, 0xbe, 0xc6, 0xd6, 0x7, 0x79, 0xbe, 0xbe, 0x9f, 0x78, 0x90, 0x2d, 0x8f, 0x82, 0x67, 0x19, 0xbf, 0xce, 0xbd, 0x5f, 0xf0, 0x99, 0xff, 0x2a, 0x3a, 0x80, 0xb5, 0xd, 0xfb, 0x64, 0xb0, 0x88, 0x4f, 0xf4, 0x32, 0xb7, 0xeb, 0x75, 0x25, 0xed, 0x1c, 0x9f, 0xee, 0xd, 0x44, 0x52, 0xbd, 0xe3, 0xb7, 0x1, 0xe1, 0xfd, 0x1f, 0x1a, 0x0, 0x23, 0xb7, 0x16, 0x67, 0x4b, 0x38, 0x59, 0xd6, 0xe1, 0xab, 0x82, 0x79, 0xa4, 0x35, 0x4c, 0xd7, 0xe4, 0x73, 0x48, 0x81, 0xa1, 0xc3, 0x7c, 0xaf, 0xa1, 0x5f, 0xe6, 0x2c, 0xee, 0x17, 0x2, 0x32, 0xd6, 0x24, 0x30, 0x25, 0xf4, 0x6f, 0x92, 0xf7, 0x31, 0x5, 0x7d, 0x96, 0x56, 0x7a, 0x23, 0x8f, 0x9f, 0x67, 0xfa, 0x9a, 0x3a, 0x23, 0xf8, 0xbf, 0x26, 0x5f, 0x61, 0x4b, 0xfb, 0x23, 0xe9, 0x89, 0x24, 0x76, 0x94, 0xb7, 0x29, 0x39, 0x34, 0x14, 0xcf, 0x8f, 0x61, 0x3c, 0xd, 0x78, 0xb9, 0x67, 0x43, 0x5f, 0x63, 0xc7, 0xc1, 0xbc, 0xab, 0x48, 0x43, 0x8e, 0x7, 0xf9, 0xfc, 0xab, 0x10, 0xe6, 0xfb, 0x5a, 0xb2, 0x55, 0xfc, 0xec, 0xf2, 0x4f, 0x89, 0xaf, 0x96, 0xf1, 0xc8, 0x9c, 0x39, 0x6e, 0xa4, 0xc5, 0xbc, 0x71, 0x4d, 0xf4, 0x49, 0x9e, 0x79, 0x8c, 0xbe, 0x7a, 0xc9, 0xed, 0xae, 0x18, 0xd8, 0xf3, 0xed, 0x3f, 0x92, 0xe, 0x91, 0xd4, 0xd7, 0x2a, 0x4e, 0xeb, 0x81, 0x3, 0x76, 0xab, 0x95, 0x73, 0x43, 0x2, 0x39, 0x9f, 0xcb, 0x9c, 0x71, 0xcd, 0xfa, 0x7c, 0xee, 0x73, 0xaa, 0x66, 0x5e, 0x19, 0xfa, 0x1b, 0xae, 0xff, 0xe, 0x1f, 0x5f, 0xa2, 0x80, 0x19, 0x8a, 0xdd, 0x10, 0x8e, 0xe7, 0x47, 0xd8, 0xdb, 0xef, 0xa4, 0x97, 0xa3, 0x0, 0xa7, 0xb0, 0xe7, 0xb9, 0x1b, 0xbd, 0xef, 0x51, 0x98, 0xbf, 0x88, 0xd9, 0xec, 0x7, 0xe8, 0xca, 0x47, 0x4d, 0xcc, 0xf3, 0x8c, 0x4b, 0xe6, 0x6b, 0xa5, 0xe8, 0x12, 0x42, 0x37, 0xb4, 0x7c, 0x42, 0x2c, 0xbb, 0xf7, 0x6, 0x2, 0x6c, 0xc2, 0x6a, 0x28, 0xf1, 0xa6, 0xcf, 0x8, 0xb6, 0xce, 0x30, 0xdb, 0x55, 0x66, 0x1f, 0x58, 0xa9, 0x3f, 0xb0, 0x62, 0xdf, 0x64, 0x7f, 0x72, 0x4, 0x6f, 0xcd, 0x86, 0xbb, 0xb4, 0xf9, 0x5d, 0x92, 0x47, 0xdf, 0x2c, 0x64, 0x78, 0x9b, 0x3c, 0xfc, 0x29, 0x44, 0x30, 0x16, 0x82, 0xb, 0xb1, 0x1a, 0x64, 0xa7, 0x8b, 0x3d, 0xe2, 0x8f, 0xe4, 0x86, 0xf5, 0x2c, 0x1, 0x62, 0x85, 0x61, 0xbe, 0xa6, 0x64, 0x33, 0xc9, 0xfe, 0xcf, 0x5b, 0x71, 0xaa, 0x45, 0x69, 0x90, 0xb1, 0xeb, 0xc0, 0x8e, 0xd2, 0x65, 0xd7, 0xb8, 0xe5, 0xf, 0x7e, 0x5d, 0xfb, 0x1d, 0xed, 0x7b, 0xff, 0xba, 0x3d, 0x5, 0xc5, 0x8a, 0x83, 0xe9, 0xa, 0x1d, 0xd8, 0xfe, 0x52, 0xf3, 0x43, 0x5b, 0x10, 0xc8, 0x5a, 0x3f, 0x9d, 0x8e, 0xfd, 0x3f, 0x6c, 0xe6, 0x7a, 0x7e, 0x13, 0x18, 0xcb, 0x8d, 0x60, 0x25, 0x1c, 0x42, 0xf0, 0xa, 0x48, 0xe0, 0xad, 0xba, 0xa3, 0xf3, 0x8, 0xbc, 0xd5, 0x12, 0xe6, 0x7b, 0xac, 0xe7, 0xc, 0x3b, 0xa, 0x30, 0xd6, 0x93, 0xdc, 0xf6, 0x33, 0xdf, 0xd9, 0x97, 0xfa, 0x23, 0x99, 0xa1, 0x3d, 0xb3, 0x20, 0xf2, 0x23, 0xf9, 0x11, 0xcb, 0xeb, 0xf8, 0xf2, 0x87, 0x9e, 0xb, 0xa4, 0x4e, 0xd2, 0xda, 0x58, 0xe6, 0x12, 0xab, 0xc0, 0xf2, 0x1e, 0x20, 0x8b, 0xc, 0x5b, 0x2f, 0xd1, 0x85, 0xa7, 0x59, 0xfd, 0xcd, 0x3d, 0x10, 0xcd, 0xe, 0xa, 0x26, 0x66, 0xc, 0xf6, 0x37, 0x77, 0xe, 0x61, 0x3c, 0x34, 0x10, 0xcd, 0xd, 0x72, 0x91, 0x4, 0x79, 0x48, 0x90, 0x3c, 0x87, 0x60, 0x4b, 0xac, 0xbe, 0x4a, 0x61, 0x4, 0x65, 0xce, 0x2b, 0xd2, 0x29, 0x78, 0xbb, 0xf4, 0x29, 0xfd, 0x5c, 0x83, 0xbf, 0xb1, 0xed, 0x3b, 0x1e, 0x49, 0xd7, 0xec, 0x25, 0xef, 0x45, 0x8e, 0xc6, 0xa7, 0xef, 0x29, 0x52, 0x6d, 0xfc, 0x4e, 0xe4, 0xc2, 0x4c, 0xfa, 0x32, 0x5d, 0xe0, 0xd1, 0x4a, 0xd, 0xe2, 0xc5, 0x61, 0xd8, 0x1d, 0x1e, 0x8c, 0x15, 0xc6, 0x53, 0xf0, 0x15, 0x2, 0x91, 0xcc, 0x26, 0x6c, 0x6c, 0x77, 0x86, 0x20, 0xbb, 0x33, 0x7f, 0x12, 0x73, 0x1b, 0xd0, 0x15, 0x87, 0xb8, 0x16, 0x34, 0xc, 0x1b, 0x8a, 0xa1, 0x33, 0x70, 0x8e, 0xd6, 0xd4, 0x66, 0x10, 0x80, 0xb1, 0xf3, 0x40, 0x37, 0x52, 0x27, 0xc4, 0xbf, 0x7c, 0xf, 0x3f, 0x18, 0x4a, 0x14, 0xc7, 0x7b, 0x7a, 0xd1, 0xa1, 0x25, 0x1c, 0x1f, 0x3f, 0xd1, 0xa, 0x25, 0x79, 0x50, 0x86, 0xef, 0xf6, 0xe3, 0x37, 0x24, 0x5d, 0xe0, 0x4f, 0x48, 0xf0, 0x16, 0xdd, 0xef, 0x27, 0xce, 0x4d, 0xd7, 0x6a, 0xc7, 0x6d, 0xcf, 0x43, 0x8a, 0xd, 0x5d, 0xd, 0x3a, 0xb4, 0xfb, 0xac, 0xc1, 0x30, 0xee, 0x70, 0x56, 0xe3, 0x3f, 0x3a, 0x5b, 0x19, 0x97, 0x9d, 0x86, 0x4e, 0x2e, 0xc6, 0x14, 0xbf, 0xf3, 0x26, 0x4f, 0x2f, 0x3d, 0xe8, 0x48, 0xcb, 0xf8, 0x1a, 0xda, 0x5f, 0x17, 0x5f, 0x55, 0xd5, 0x77, 0xa4, 0xfd, 0xf8, 0xd, 0x9, 0x94, 0x9, 0xc6, 0x35, 0x8b, 0x71, 0x89, 0x8e, 0xb0, 0x8f, 0xfb, 0xef, 0x6, 0x76, 0x9f, 0x3d, 0x38, 0x18, 0xcd, 0x36, 0xf2, 0xd8, 0xc5, 0x2e, 0x5c, 0x73, 0xb8, 0x7d, 0xde, 0x30, 0x7, 0x38, 0x97, 0x39, 0xa0, 0x27, 0x11, 0xe6, 0x13, 0x5c, 0x73, 0xf2, 0x4e, 0x4f, 0x2f, 0x3f, 0x2, 0xb1, 0xdc, 0x12, 0x74, 0x28, 0xde, 0x3d, 0x48, 0xf1, 0xcd, 0xf1, 0x21, 0xad, 0xcf, 0xe7, 0x7d, 0x8f, 0xe8, 0x2, 0xe6, 0xeb, 0xd5, 0x39, 0x73, 0xde, 0xb5, 0xb1, 0x7e, 0xce, 0xe2, 0x3c, 0x67, 0x89, 0xe8, 0xad, 0x3, 0x5c, 0xf, 0x3a, 0xb4, 0xdb, 0x8c, 0x61, 0xb4, 0xa5, 0xcf, 0xb4, 0xf6, 0xa3, 0x3b, 0x69, 0x17, 0xe8, 0xd2, 0xf5, 0x28, 0xc6, 0x5a, 0xf1, 0xef, 0x5d, 0x3a, 0x71, 0x87, 0xb, 0xc1, 0xb8, 0xb2, 0x51, 0xf6, 0xd2, 0xa9, 0x1e, 0xd1, 0xf3, 0x21, 0xb2, 0x5e, 0x50, 0xba, 0x4d, 0x5e, 0x7e, 0x7d, 0x10, 0x8c, 0x65, 0x1b, 0xea, 0xd0, 0xfa, 0x72, 0x61, 0x8, 0xf0, 0x35, 0x28, 0xc3, 0x7e, 0xc7, 0x80, 0xbe, 0x12, 0x80, 0xc9, 0xa9, 0x3b, 0xf8, 0xce, 0x1f, 0xe7, 0xe9, 0x43, 0x7, 0x4f, 0x26, 0xd, 0x90, 0xe0, 0x1d, 0xc9, 0x89, 0x42, 0x2a, 0x89, 0xab, 0x2e, 0xc0, 0x5e, 0x5, 0xec, 0x3, 0xdc, 0xff, 0x21, 0x29, 0xef, 0x6, 0x1e, 0xe4, 0xf5, 0xe9, 0xbf, 0xe, 0x13, 0x80, 0xa4, 0x21, 0x9b, 0x93, 0xaf, 0xf0, 0xd4, 0xb1, 0xb9, 0xa7, 0xf, 0x1e, 0x90, 0xe0, 0x78, 0x56, 0xe1, 0xaf, 0x5a, 0x1c, 0x75, 0x2e, 0xbe, 0xe4, 0xf, 0x19, 0x49, 0x5f, 0xec, 0x6e, 0xfb, 0x8f, 0x17, 0xc6, 0x12, 0xe4, 0x4f, 0x55, 0xe3, 0x9d, 0x40, 0xa4, 0x2d, 0x18, 0x3a, 0x7e, 0x66, 0x77, 0x7d, 0x8c, 0xa7, 0x8f, 0x1e, 0x10, 0x77, 0x2c, 0x5, 0x68, 0x97, 0x78, 0x94, 0xc4, 0x26, 0xd2, 0x45, 0x60, 0x43, 0x0, 0x1, 0x52, 0xf7, 0xb2, 0x2f, 0x59, 0xde, 0x95, 0x0, 0xb5, 0x7f, 0xbf, 0xd2, 0x9a, 0x37, 0x80, 0x0, 0xbf, 0x6b, 0xc6, 0x2, 0xcd, 0x4, 0xd9, 0xdc, 0x89, 0xec, 0x3e, 0x8, 0xa0, 0xaa, 0x7, 0xc9, 0xae, 0x3a, 0xcd, 0xcb, 0x96, 0x29, 0x9e, 0x3e, 0x7c, 0x4, 0xe3, 0x85, 0xb5, 0x28, 0xc2, 0xe3, 0x46, 0x61, 0x9a, 0x91, 0xb, 0x9a, 0x13, 0x8b, 0x31, 0xd2, 0x72, 0xde, 0x9c, 0x47, 0x91, 0x7f, 0xb3, 0x88, 0x4e, 0x77, 0x25, 0x38, 0x94, 0xf, 0x44, 0xf9, 0x75, 0xb4, 0xe9, 0xbf, 0xab, 0x6, 0x93, 0x8e, 0x0, 0x5d, 0x4, 0x94, 0xfa, 0x90, 0xbd, 0xc5, 0xe, 0x9e, 0x7e, 0x70, 0xb0, 0x2, 0x8f, 0xaf, 0xc6, 0x94, 0x2c, 0x49, 0x8c, 0x75, 0x1, 0x36, 0x95, 0x26, 0xd9, 0x8, 0xa6, 0x5d, 0xfc, 0x5d, 0x60, 0xf2, 0xb, 0xd8, 0x87, 0xa1, 0x94, 0x16, 0x60, 0x19, 0xd9, 0x3d, 0x44, 0xb4, 0xcf, 0x57, 0x1c, 0x56, 0x9a, 0x1e, 0x88, 0x75, 0x1, 0xab, 0x67, 0x54, 0x7f, 0x20, 0x0, 0x71, 0x4, 0xd9, 0x8c, 0xdd, 0x6b, 0xe4, 0x87, 0x18, 0xe7, 0x92, 0x7, 0xa4, 0x13, 0x90, 0x7c, 0xa2, 0xf, 0x2, 0x4c, 0x5f, 0x7a, 0xe7, 0x96, 0x81, 0xce, 0x7, 0x96, 0x98, 0xbe, 0xb8, 0x5f, 0xa, 0x86, 0xa1, 0x8a, 0x31, 0xbb, 0xa8, 0xea, 0x4a, 0x7f, 0x45, 0xd2, 0x8c, 0x8d, 0x5f, 0x3f, 0x21, 0x41, 0xdc, 0x66, 0x9e, 0xba, 0x91, 0x47, 0x91, 0xd1, 0xcc, 0x5d, 0x81, 0x78, 0x61, 0x61, 0x67, 0x5f, 0x0, 0xed, 0x71, 0xe3, 0xe0, 0x40, 0xac, 0x10, 0xa3, 0x55, 0xff, 0x7, 0x24, 0xb0, 0x74, 0xb9, 0xbb, 0x40, 0x87, 0x21, 0x79, 0x8e, 0xbe, 0x90, 0x77, 0xb, 0x53, 0xfa, 0x13, 0x1, 0x58, 0x2c, 0xeb, 0x10, 0xdf, 0xb7, 0xa0, 0xec, 0x26, 0xc8, 0x9f, 0xd4, 0x21, 0xa5, 0x18, 0x4b, 0x5e, 0x33, 0xaf, 0x53, 0xab, 0xd, 0xdd, 0xd8, 0xe5, 0x5e, 0xd, 0xc3, 0x84, 0x0, 0x69, 0xfb, 0x68, 0xc6, 0x69, 0x58, 0x1b, 0x4a, 0x4c, 0xdf, 0xd5, 0xd3, 0xcf, 0x8e, 0xf0, 0xee, 0x33, 0x27, 0xb2, 0x61, 0x3e, 0x5d, 0x62, 0x55, 0x5a, 0xac, 0xee, 0x14, 0x5e, 0x8a, 0x8f, 0xd4, 0xc0, 0xea, 0x7f, 0x9f, 0xee, 0x73, 0x56, 0x30, 0x3e, 0x7d, 0x39, 0x9b, 0xc, 0x2e, 0xe, 0xf, 0xed, 0x36, 0x73, 0x51, 0x14, 0xad, 0x1f, 0x88, 0x17, 0x23, 0xc1, 0x78, 0xf1, 0x40, 0x56, 0xea, 0x1b, 0x18, 0x2c, 0x1, 0xcd, 0x90, 0x6d, 0x88, 0x9e, 0x4f, 0x43, 0x89, 0x19, 0x6b, 0x7a, 0xfa, 0xe1, 0x11, 0xde, 0x6d, 0xe6, 0xca, 0x5a, 0x8c, 0x8e, 0xe6, 0xcb, 0xac, 0x8b, 0xc2, 0x9b, 0xe6, 0xbe, 0xd, 0xc6, 0xf3, 0xb3, 0x58, 0x4c, 0xdb, 0xfb, 0xe2, 0x33, 0x7, 0x77, 0xa3, 0xe0, 0x33, 0xc6, 0x51, 0xec, 0x55, 0x29, 0xf4, 0xe, 0xb4, 0xaf, 0x4, 0xf2, 0x68, 0x98, 0xd4, 0xc9, 0xe6, 0xec, 0x9d, 0x40, 0x4, 0x63, 0x20, 0x18, 0x35, 0xa0, 0x19, 0x56, 0xda, 0xd8, 0x6, 0xaa, 0xce, 0xc7, 0xa, 0x47, 0x62, 0x7b, 0x74, 0x7f, 0x24, 0x0, 0xb, 0x68, 0x45, 0xf2, 0xf7, 0x83, 0xe4, 0xce, 0x9, 0x28, 0x73, 0xee, 0x91, 0xac, 0xfa, 0xcc, 0xf7, 0xd8, 0xb8, 0x8f, 0x7a, 0x1d, 0x1a, 0xde, 0x7d, 0xd6, 0xc4, 0xee, 0x32, 0x75, 0x1a, 0x2b, 0xfe, 0x30, 0x1e, 0xc3, 0xde, 0x92, 0x62, 0xeb, 0xc0, 0x68, 0x56, 0x87, 0x32, 0xcf, 0xd9, 0x84, 0x2, 0x15, 0x5d, 0x7c, 0xf7, 0xaf, 0xe6, 0xe9, 0xa7, 0x7, 0xc4, 0x5e, 0x96, 0xe2, 0x3c, 0x23, 0x39, 0x53, 0x8e, 0xe4, 0x4d, 0xea, 0x80, 0xde, 0x2f, 0x59, 0xf1, 0x4f, 0x51, 0xf8, 0x13, 0x58, 0xb0, 0xa3, 0x6c, 0xb6, 0xaa, 0x19, 0xff, 0x73, 0x77, 0xce, 0x51, 0x96, 0x2b, 0x69, 0x0, 0x3f, 0xe7, 0xd9, 0xb6, 0xed, 0x77, 0xb5, 0xb6, 0x6d, 0x7b, 0xdb, 0x5a, 0xdb, 0xb6, 0x6d, 0x7b, 0x9b, 0xd7, 0xcd, 0x35, 0x9f, 0xcd, 0xb1, 0x6d, 0xab, 0xbb, 0xb2, 0xbf, 0x4a, 0xbe, 0x4c, 0x32, 0x75, 0x36, 0xe7, 0x4e, 0xcf, 0xad, 0x34, 0xf2, 0xc7, 0xef, 0x54, 0xa5, 0x92, 0xfb, 0xb9, 0xaa, 0x82, 0xc1, 0x5b, 0x49, 0xfe, 0x3a, 0x84, 0x22, 0x98, 0xa, 0x3, 0x1e, 0x25, 0x1c, 0x4d, 0xa8, 0x2f, 0xfc, 0x1e, 0x22, 0x8e, 0x27, 0x89, 0xd6, 0xc7, 0x2c, 0x79, 0x6c, 0x52, 0xb, 0x0, 0xdf, 0x4e, 0x25, 0x41, 0x9f, 0xc2, 0xcf, 0x88, 0x18, 0xfc, 0x5e, 0x30, 0x8e, 0x5, 0xf3, 0x5c, 0x38, 0x6e, 0x24, 0xfd, 0xbd, 0xd7, 0xbd, 0xb1, 0xfb, 0x70, 0x5b, 0x5f, 0xf7, 0x3e, 0x4d, 0x1, 0xf0, 0x1a, 0x36, 0x30, 0x82, 0xbe, 0x92, 0x7e, 0x6c, 0xf0, 0xc2, 0x64, 0xd7, 0x8d, 0x8d, 0x7d, 0x8f, 0x12, 0x33, 0x92, 0x5a, 0x4, 0x4f, 0x94, 0xb8, 0x5a, 0x8b, 0x27, 0xb9, 0xda, 0x74, 0x63, 0x43, 0xdf, 0xa9, 0x16, 0x97, 0xaa, 0xee, 0x9f, 0x22, 0x14, 0xe1, 0x7f, 0x70, 0xa4, 0xd, 0x61, 0x1c, 0xd7, 0x42, 0x8c, 0xac, 0x71, 0x5e, 0xc9, 0xf1, 0xd2, 0x54, 0x63, 0x7f, 0x3a, 0xc9, 0x5, 0xc0, 0xbe, 0x7c, 0x6d, 0x10, 0x57, 0x30, 0xe2, 0x74, 0x70, 0xf1, 0xa2, 0x15, 0x19, 0x1a, 0x96, 0xfe, 0xed, 0x99, 0xe6, 0xfc, 0xb9, 0x16, 0x5f, 0x5a, 0x74, 0xf7, 0x6a, 0x45, 0x8, 0xd6, 0x28, 0x69, 0xa7, 0x80, 0x3f, 0xde, 0x94, 0x6a, 0xea, 0xbf, 0x3a, 0xd1, 0x5, 0xd0, 0x9c, 0xbf, 0x6, 0x5f, 0x27, 0x2c, 0xc7, 0x6e, 0x77, 0xba, 0x69, 0xe0, 0x3c, 0x8b, 0xcb, 0x54, 0x6f, 0x51, 0xaa, 0x4c, 0xf1, 0xb5, 0xcf, 0x89, 0x1b, 0xf4, 0x78, 0x6d, 0x43, 0xcf, 0x40, 0xaa, 0x69, 0xe0, 0xe2, 0x24, 0x17, 0x0, 0x33, 0xf5, 0x4a, 0x7c, 0x5d, 0x2f, 0x3e, 0xdb, 0x62, 0x3c, 0xdd, 0x3c, 0xad, 0x5, 0xd0, 0x1d, 0x3d, 0x2e, 0x44, 0x9f, 0xb, 0x40, 0xef, 0xf7, 0xd8, 0x2, 0xce, 0x4e, 0xf8, 0xa, 0x70, 0x19, 0x2b, 0xec, 0x82, 0x20, 0x6, 0xd2, 0x46, 0xc7, 0x25, 0x32, 0xd6, 0x37, 0xa, 0x29, 0xa0, 0xb0, 0xce, 0xb7, 0x79, 0xa3, 0x52, 0x14, 0xe1, 0xea, 0x0, 0x43, 0x1a, 0xa4, 0x8d, 0xa2, 0x21, 0x7a, 0xac, 0xd6, 0xef, 0x5d, 0x7d, 0xd, 0xc9, 0x2f, 0x80, 0x54, 0x93, 0x14, 0x0, 0x3e, 0xd7, 0x4b, 0x50, 0x0, 0xdd, 0x14, 0x40, 0xc1, 0x5e, 0x1, 0xa4, 0x75, 0x1, 0x78, 0xa, 0x94, 0x4e, 0x9a, 0x1, 0xf4, 0x84, 0xe8, 0x3e, 0x34, 0x8c, 0xdf, 0x6a, 0x7d, 0x14, 0x40, 0x9e, 0x0, 0x5d, 0x9c, 0xec, 0x15, 0xa0, 0x70, 0x25, 0xbe, 0x6e, 0xa8, 0x15, 0x1b, 0xa8, 0xd1, 0x7, 0xe9, 0x23, 0x6f, 0x3c, 0xd5, 0x68, 0x75, 0xb, 0xe8, 0xeb, 0xe5, 0x8d, 0x1c, 0x82, 0x5d, 0x25, 0xa, 0x9c, 0x98, 0x11, 0x5d, 0xbd, 0x37, 0x11, 0xa0, 0x44, 0xdf, 0x4, 0x66, 0x5a, 0x8a, 0xd7, 0xe8, 0x98, 0xe2, 0xaf, 0xcd, 0xd8, 0xed, 0x4e, 0x59, 0xbd, 0x9, 0x6c, 0xea, 0xff, 0xe9, 0x8d, 0x5a, 0x30, 0xb0, 0x2f, 0x7, 0xec, 0x3f, 0xa6, 0x5, 0x12, 0x6, 0x72, 0x2c, 0xd7, 0x4, 0x63, 0x26, 0xe6, 0xb5, 0xe1, 0xeb, 0x9, 0x8, 0xb2, 0xe9, 0x2f, 0xa5, 0x0, 0x52, 0xc9, 0x2e, 0x80, 0xc2, 0xb5, 0x7e, 0xc, 0x25, 0x1e, 0x26, 0x46, 0xbc, 0x8c, 0x6b, 0x18, 0xf3, 0x5a, 0x81, 0x3e, 0xb1, 0xdb, 0x4e, 0xdc, 0xce, 0xb5, 0xf8, 0xac, 0x9a, 0xff, 0x34, 0x8a, 0xb6, 0x84, 0x92, 0x1e, 0x37, 0x52, 0xc9, 0x3d, 0xbb, 0x52, 0xcd, 0x85, 0x47, 0x25, 0x7c, 0x5, 0x78, 0x8a, 0xf8, 0xab, 0xec, 0xc5, 0xae, 0x77, 0x13, 0x5, 0x70, 0xb2, 0xc5, 0x15, 0x60, 0xe0, 0x2d, 0x6c, 0x3, 0xeb, 0x74, 0xb5, 0x71, 0x3f, 0x0, 0xbd, 0xca, 0x6d, 0x41, 0xc6, 0xac, 0xe3, 0xaf, 0x1c, 0x38, 0xf2, 0xd8, 0xc4, 0xee, 0xff, 0x2d, 0xc5, 0xd3, 0x88, 0xed, 0x67, 0x6d, 0xc7, 0x90, 0x89, 0x43, 0xdc, 0xf2, 0x5f, 0xe6, 0x25, 0xd3, 0x61, 0x76, 0xaa, 0xb4, 0xb5, 0x74, 0x1, 0x37, 0x63, 0x9d, 0xbc, 0x5c, 0xf8, 0x7b, 0xa, 0x5, 0x1, 0x18, 0x2e, 0x7d, 0xbe, 0x6f, 0xab, 0xb4, 0xd7, 0x42, 0xbf, 0x10, 0x36, 0xac, 0x5f, 0xda, 0x10, 0xe6, 0xf5, 0x72, 0xd, 0x72, 0x15, 0xc7, 0x9e, 0xdc, 0xe6, 0x62, 0x52, 0xb, 0x80, 0xb8, 0x96, 0xaf, 0x61, 0x7b, 0xbd, 0xfd, 0x46, 0xb7, 0x0, 0x24, 0x5e, 0x12, 0xb3, 0x50, 0x1f, 0xcc, 0x78, 0x1a, 0xc8, 0x78, 0x28, 0x7e, 0xd0, 0xb7, 0x89, 0x7c, 0xfd, 0x83, 0x42, 0xf8, 0x6c, 0xba, 0xa5, 0x74, 0x8a, 0x8d, 0x6a, 0x3d, 0x1e, 0x41, 0x37, 0x30, 0x23, 0x9f, 0x9b, 0x6e, 0x29, 0x34, 0xd2, 0x7e, 0x12, 0xe1, 0xbf, 0xc4, 0x81, 0x3b, 0x30, 0x6e, 0xf, 0x38, 0x3e, 0x28, 0x57, 0xb4, 0x1a, 0xa7, 0xe, 0x94, 0x57, 0x0, 0x85, 0xf, 0x64, 0xdb, 0xaa, 0x27, 0x26, 0xb3, 0x0, 0x4a, 0x39, 0x9d, 0x28, 0x10, 0x9f, 0xeb, 0x23, 0x15, 0x9e, 0x8c, 0xc1, 0xd8, 0x16, 0xa, 0xe1, 0x6f, 0x4c, 0xe0, 0xf7, 0x90, 0xc3, 0x33, 0xac, 0x19, 0x9f, 0x6b, 0x1f, 0x3c, 0x91, 0xa, 0xbe, 0x98, 0x19, 0xfa, 0x38, 0xda, 0x97, 0xd2, 0xb6, 0xa3, 0xe8, 0x7e, 0x14, 0x4e, 0xa0, 0xd8, 0x9a, 0x43, 0x14, 0xd8, 0xca, 0x6c, 0x6b, 0xf9, 0x9, 0x9, 0xdd, 0x2, 0x1e, 0xe5, 0x27, 0xdf, 0x52, 0x11, 0x28, 0x21, 0x98, 0x88, 0x22, 0x9b, 0x8f, 0x6a, 0x1b, 0xd8, 0x6e, 0xca, 0xe8, 0x7c, 0x4d, 0xae, 0xad, 0x7c, 0x64, 0x5c, 0xe, 0x7d, 0x87, 0x22, 0x18, 0x7, 0x9d, 0x38, 0x87, 0xb6, 0x2e, 0x90, 0xa1, 0xc0, 0x61, 0xe5, 0x79, 0x4d, 0xd2, 0x92, 0xcf, 0xaa, 0x76, 0x3a, 0xf1, 0xfa, 0x9c, 0xc4, 0x49, 0x4d, 0x3e, 0x3e, 0x35, 0xe3, 0xab, 0xcc, 0x38, 0x8a, 0xae, 0x25, 0xe8, 0xfd, 0x52, 0xba, 0xa5, 0x7c, 0x83, 0x55, 0x87, 0x72, 0x9d, 0x23, 0x47, 0x30, 0x53, 0xdf, 0x80, 0x61, 0xe3, 0xae, 0xa2, 0xe6, 0x1, 0x5, 0xce, 0xc1, 0x93, 0x17, 0xa4, 0xef, 0xc9, 0x70, 0xc1, 0xe0, 0x6f, 0x66, 0xdb, 0xca, 0x67, 0x27, 0xab, 0x0, 0x2a, 0x4f, 0x26, 0x19, 0xeb, 0x3, 0x3f, 0xf3, 0x66, 0x1c, 0x26, 0x43, 0xf4, 0x6f, 0x49, 0xbe, 0xf4, 0x69, 0xc1, 0xd5, 0x97, 0x7f, 0x88, 0xed, 0xe7, 0x59, 0x71, 0xdc, 0xd4, 0x5c, 0xe2, 0x57, 0x1e, 0xef, 0xa2, 0x15, 0x38, 0x36, 0xc0, 0xe0, 0xb5, 0xc8, 0x7e, 0x41, 0xc2, 0xf6, 0xff, 0x26, 0x99, 0xa1, 0x76, 0xe2, 0x24, 0xa4, 0xa3, 0xcf, 0x29, 0xf0, 0x56, 0x84, 0xe6, 0xfc, 0x70, 0xb6, 0xbd, 0x7a, 0x41, 0x5c, 0x2f, 0x36, 0x56, 0x84, 0x95, 0xd1, 0x1a, 0x14, 0x4, 0xfa, 0x46, 0xb, 0xe6, 0xb8, 0xd2, 0x20, 0x7, 0xc7, 0x8a, 0xdf, 0xc8, 0xb4, 0x55, 0x4f, 0x4e, 0xc4, 0xde, 0xdf, 0x5a, 0x4e, 0xe3, 0xcf, 0x5f, 0xd3, 0x4d, 0x92, 0x34, 0x29, 0x82, 0x38, 0x11, 0x5d, 0x12, 0xcb, 0x42, 0x8f, 0xfc, 0x27, 0x96, 0xd6, 0xbf, 0x6c, 0x1d, 0x96, 0x69, 0x29, 0xfd, 0x80, 0x76, 0xf, 0x38, 0x14, 0x83, 0x15, 0x90, 0x5, 0x85, 0xa5, 0xec, 0x5b, 0xaf, 0x4c, 0xc8, 0xe3, 0xdf, 0x47, 0x24, 0x3e, 0x4a, 0xda, 0x29, 0x1, 0x5d, 0xa2, 0xaf, 0xf4, 0xeb, 0x58, 0x1c, 0xd3, 0xff, 0x3a, 0x55, 0xa6, 0xb5, 0xf2, 0x54, 0x1e, 0x39, 0x76, 0x90, 0x30, 0x14, 0x15, 0x95, 0x28, 0x17, 0x8a, 0x61, 0x6a, 0x18, 0x5c, 0xf4, 0x8d, 0x76, 0xe5, 0x68, 0x79, 0x2c, 0x9b, 0xbf, 0x47, 0xfe, 0x39, 0xb3, 0x3b, 0xf9, 0x95, 0x27, 0xe3, 0xcf, 0xcd, 0x7e, 0x42, 0x82, 0x38, 0xd0, 0xd6, 0x8e, 0x55, 0x8d, 0x31, 0xe3, 0xd8, 0x40, 0x26, 0xd2, 0x2e, 0xee, 0x3f, 0x3e, 0x19, 0xdf, 0xcd, 0x4d, 0xfb, 0xd0, 0x89, 0xbc, 0xbe, 0xdd, 0x24, 0x5, 0xe0, 0x48, 0x5b, 0x17, 0xfb, 0x65, 0xb5, 0x14, 0xb7, 0x13, 0xc0, 0x8f, 0xcc, 0xd6, 0xe4, 0xe7, 0x3a, 0x86, 0x4e, 0x66, 0xf6, 0xff, 0x42, 0xfc, 0x91, 0xe4, 0x4f, 0x9, 0xca, 0x9f, 0x44, 0xc4, 0x70, 0x8c, 0x18, 0xa6, 0xe2, 0x5e, 0xe2, 0x46, 0x51, 0xb4, 0x17, 0xf4, 0xac, 0xb5, 0x81, 0xd2, 0xa4, 0x5d, 0x67, 0x4a, 0xf, 0xe2, 0xc0, 0x8b, 0x67, 0xe9, 0xa3, 0xdf, 0xc7, 0xf0, 0x61, 0x47, 0xfd, 0x71, 0x29, 0x4e, 0xfe, 0x3a, 0x89, 0x1f, 0xf7, 0x1f, 0x5f, 0x9d, 0x8a, 0x4a, 0xbf, 0x6, 0x65, 0xab, 0x33, 0x35, 0x1c, 0xcd, 0xa, 0xc6, 0x58, 0xe4, 0x31, 0xc9, 0x9f, 0xf0, 0xb6, 0x82, 0xf2, 0xf0, 0x23, 0x3a, 0x87, 0x4f, 0x9a, 0x55, 0xc9, 0x6f, 0x1f, 0x6c, 0xc0, 0xfe, 0x85, 0xe2, 0x8b, 0x3b, 0x23, 0xa3, 0x7c, 0xae, 0x35, 0x6e, 0x9e, 0x97, 0x36, 0x1a, 0x3f, 0xf, 0x5e, 0x1, 0x7c, 0x32, 0x76, 0x67, 0x1f, 0xd9, 0x35, 0x76, 0x34, 0x2f, 0x6f, 0x96, 0x7b, 0xc6, 0x95, 0xad, 0x40, 0xf0, 0x94, 0xb4, 0x1e, 0x6d, 0x95, 0xa1, 0x59, 0xb4, 0xf4, 0x3f, 0x86, 0x7d, 0xf7, 0x56, 0x89, 0x87, 0x2, 0x67, 0xa, 0x51, 0x1a, 0x1d, 0x33, 0x26, 0xce, 0x5c, 0x9e, 0xa4, 0x5e, 0x11, 0xab, 0xb3, 0x8f, 0xe8, 0xfa, 0xd3, 0x11, 0x54, 0x7b, 0x27, 0xca, 0x36, 0x83, 0x93, 0x6d, 0xb3, 0x87, 0xe, 0x20, 0x2d, 0x33, 0x47, 0xfa, 0xed, 0xd5, 0xea, 0xcc, 0x4f, 0xfe, 0x70, 0x8e, 0x2d, 0xeb, 0x1e, 0xdf, 0x76, 0x90, 0xb6, 0xae, 0x38, 0x44, 0xca, 0x89, 0x1a, 0xf7, 0x72, 0x31, 0xf8, 0xb9, 0x78, 0x9d, 0xed, 0x1a, 0x3b, 0x82, 0x6a, 0xff, 0x30, 0xca, 0xf6, 0x7a, 0xa, 0x2b, 0x4a, 0x5a, 0x6b, 0x84, 0xe5, 0xa6, 0x5b, 0xd0, 0xd3, 0x56, 0x2d, 0xcc, 0xdc, 0x65, 0x7f, 0x38, 0x4b, 0x91, 0xce, 0xd1, 0xb6, 0x82, 0x12, 0x1f, 0x94, 0xa5, 0x38, 0x28, 0x5f, 0xae, 0x81, 0x13, 0xc1, 0x38, 0xb9, 0x69, 0x8f, 0xd3, 0xd9, 0xa3, 0x98, 0xf9, 0x5f, 0xa2, 0xda, 0xc7, 0x41, 0x12, 0x55, 0x55, 0xf4, 0x75, 0x2b, 0x84, 0xfb, 0xe1, 0x31, 0xf3, 0x9a, 0xe8, 0xeb, 0x90, 0x17, 0xc8, 0xe5, 0x58, 0xf4, 0xdd, 0xc4, 0xd3, 0xc7, 0x69, 0x33, 0x6b, 0xe6, 0x8f, 0x3c, 0x83, 0xfd, 0x76, 0x19, 0xb6, 0x19, 0x13, 0xa1, 0xaa, 0x20, 0xc2, 0x3f, 0x21, 0x7a, 0x4c, 0xc0, 0x6f, 0x66, 0x39, 0x68, 0xff, 0x77, 0x72, 0x7c, 0x3f, 0x13, 0x61, 0x5, 0x13, 0x62, 0x27, 0x5b, 0xaf, 0x1e, 0x73, 0xf1, 0xfa, 0x65, 0xb7, 0xcf, 0xf9, 0x3b, 0xb2, 0x1d, 0xc3, 0x4f, 0x8f, 0x69, 0xd9, 0x1f, 0x3b, 0x8e, 0x4, 0x7c, 0x27, 0xdd, 0x5a, 0x99, 0xc8, 0x60, 0x1c, 0x55, 0xef, 0x3a, 0x2a, 0xfd, 0x43, 0xa3, 0xcd, 0xe8, 0xb, 0xa6, 0x5c, 0xfa, 0x8a, 0x40, 0x43, 0x65, 0x43, 0xa6, 0x7d, 0x68, 0x46, 0x7c, 0x35, 0xcc, 0xb4, 0xd, 0x7e, 0x8a, 0x80, 0x6f, 0xd4, 0x76, 0x82, 0x97, 0x74, 0xb1, 0xb5, 0xb6, 0xcf, 0xb5, 0x10, 0x59, 0x81, 0xec, 0x7f, 0x7b, 0xdf, 0x62, 0x46, 0x8f, 0xce, 0x76, 0x78, 0xf0, 0x5d, 0xe6, 0x1c, 0xa, 0xf0, 0x6, 0xe2, 0xf1, 0x64, 0x92, 0xfe, 0x12, 0x72, 0xf3, 0x56, 0xda, 0xc7, 0x30, 0x76, 0x78, 0xc, 0xc9, 0x1f, 0x3d, 0x81, 0x7d, 0xee, 0x93, 0xcc, 0xfe, 0xa0, 0xb2, 0xe9, 0x83, 0x73, 0xf0, 0x54, 0xa5, 0x9d, 0x14, 0x4a, 0x74, 0x86, 0x67, 0xd6, 0x16, 0x9c, 0xed, 0x79, 0xf4, 0xbb, 0x6e, 0x8a, 0x7e, 0xcd, 0x19, 0xef, 0xfd, 0xcf, 0xd1, 0xe8, 0x9f, 0xeb, 0xcd, 0xca, 0xfd, 0x3e, 0x29, 0xeb, 0x31, 0xc1, 0x57, 0xdd, 0xb2, 0xa4, 0xdf, 0x49, 0xe2, 0x4f, 0xfd, 0x7f, 0xb6, 0xe8, 0x18, 0x60, 0xc7, 0x61, 0xe4, 0xe7, 0x70, 0xf2, 0x73, 0x24, 0xd7, 0x1f, 0x66, 0xdd, 0x61, 0xaa, 0xea, 0x78, 0xe8, 0xe4, 0xe6, 0x62, 0x42, 0x3b, 0x99, 0xc3, 0x49, 0x8d, 0xf4, 0xe3, 0x45, 0x2, 0x21, 0x7d, 0x25, 0x38, 0xb0, 0x87, 0xc0, 0x2c, 0xcd, 0x52, 0x94, 0xa9, 0x96, 0xca, 0x91, 0x53, 0x91, 0x78, 0x66, 0x1a, 0x1, 0x1e, 0x2a, 0xa2, 0x77, 0x65, 0x78, 0xb5, 0xf2, 0x6d, 0xb2, 0x85, 0x11, 0xdb, 0x7d, 0xe8, 0xfc, 0xcd, 0x74, 0xef, 0x73, 0x4f, 0xcf, 0xba, 0xc6, 0xc, 0xb9, 0x15, 0xae, 0xdb, 0x30, 0x4, 0xc4, 0x3c, 0x6, 0xa3, 0xf, 0x91, 0xbf, 0x33, 0xae, 0x8d, 0xb8, 0x46, 0x85, 0xce, 0x2b, 0x19, 0xd3, 0xf6, 0x6c, 0xa5, 0xf2, 0xef, 0x63, 0x39, 0xfc, 0x44, 0xae, 0x73, 0xec, 0xc4, 0x98, 0xb6, 0xbe, 0x2c, 0x85, 0xf6, 0x1b, 0x96, 0xfc, 0x85, 0x2c, 0xf9, 0x7b, 0xfd, 0x19, 0xea, 0xdb, 0x22, 0x31, 0x89, 0xf0, 0x25, 0x2a, 0x46, 0x35, 0xe3, 0x25, 0x2b, 0xc9, 0xd0, 0xdf, 0x1f, 0xf5, 0xb6, 0xbf, 0x1e, 0x3d, 0xbd, 0x77, 0xb9, 0x1d, 0x23, 0xd7, 0x63, 0xc8, 0x9d, 0xbe, 0x71, 0xfe, 0xb2, 0x2c, 0xc7, 0x53, 0xc9, 0x1, 0x3a, 0x7d, 0x1b, 0x24, 0x50, 0x9b, 0x28, 0x84, 0xb9, 0x24, 0xea, 0x57, 0xd8, 0xfb, 0x4a, 0xf6, 0xc8, 0x93, 0xeb, 0xf4, 0x39, 0x45, 0xe1, 0x7f, 0x94, 0xc2, 0xfa, 0x1b, 0xb2, 0x17, 0xc1, 0x2e, 0x3f, 0xf1, 0xa2, 0xd7, 0xd7, 0x6d, 0xdd, 0xc7, 0xc0, 0xaf, 0xa1, 0xc5, 0xe8, 0x7f, 0xf3, 0xcc, 0xb8, 0xdb, 0xed, 0x1c, 0x7d, 0x3e, 0x6, 0x39, 0x30, 0x41, 0xa0, 0x9d, 0x69, 0x46, 0xb9, 0x48, 0x5f, 0xec, 0xd2, 0x7d, 0xdd, 0xee, 0xa6, 0x8, 0x16, 0xc3, 0xed, 0x30, 0x44, 0x22, 0xbf, 0xc9, 0xc, 0x7e, 0x1d, 0xab, 0x43, 0x9a, 0xfe, 0x85, 0xf4, 0x4f, 0xcd, 0x75, 0xfd, 0xe9, 0x44, 0x38, 0xee, 0x91, 0x6f, 0xfd, 0xcb, 0x89, 0x8c, 0x9d, 0x41, 0xb1, 0x5c, 0xc4, 0xf8, 0xe3, 0xd8, 0x47, 0xdf, 0xc3, 0xf1, 0x0, 0xbf, 0xbb, 0x9, 0xee, 0x67, 0xc6, 0xaf, 0xf7, 0x65, 0x83, 0xa9, 0x57, 0x8f, 0x49, 0xbf, 0x7e, 0x4c, 0x79, 0xf4, 0x27, 0xb0, 0xe5, 0x7f, 0xed, 0x9c, 0x3, 0x90, 0x2c, 0x49, 0x13, 0x80, 0xfb, 0xff, 0xcf, 0xb6, 0x6d, 0x6b, 0x7a, 0xe6, 0x6c, 0xdb, 0xb6, 0x6f, 0x7d, 0xb6, 0x6d, 0xdb, 0x76, 0xe0, 0x7c, 0xb7, 0xec, 0x99, 0xd5, 0xd9, 0xb6, 0x6d, 0x63, 0xdf, 0x54, 0xdd, 0x57, 0xbd, 0x39, 0x13, 0xf5, 0x2a, 0x5e, 0x5f, 0xaf, 0x63, 0xd0, 0x19, 0xf1, 0x45, 0x66, 0x55, 0x67, 0xd6, 0x54, 0x67, 0x66, 0xf5, 0xcc, 0xf2, 0x8a, 0xb5, 0x8f, 0x7b, 0xf9, 0x7f, 0x5e, 0x29, 0x8, 0x49, 0x9a, 0x8d, 0xd, 0x75, 0x93, 0x18, 0x4d, 0x57, 0x2, 0x9b, 0x24, 0x19, 0x46, 0x8f, 0xd, 0x4f, 0x58, 0xc8, 0x9c, 0xec, 0xc1, 0xb5, 0xd1, 0x36, 0xbf, 0x11, 0xf3, 0x1, 0x7b, 0x7f, 0x9e, 0x2f, 0x61, 0x7b, 0xfd, 0x9a, 0x27, 0x72, 0x7e, 0x4d, 0x73, 0x0, 0x1d, 0x8c, 0x3, 0x4e, 0x79, 0x27, 0xf4, 0x72, 0xfd, 0x65, 0x7c, 0xbf, 0x2, 0xed, 0xc2, 0x9a, 0xb2, 0xee, 0xf0, 0xef, 0x1, 0xed, 0xe2, 0xee, 0x3d, 0xf, 0x9a, 0x3d, 0x35, 0xaf, 0x50, 0xd3, 0x3c, 0xaf, 0x57, 0x2a, 0xc2, 0x9, 0x9a, 0x88, 0x6f, 0x0, 0xad, 0x27, 0x49, 0x51, 0x6, 0x29, 0x48, 0x29, 0x61, 0xf6, 0x55, 0xb4, 0xad, 0xf9, 0x62, 0x31, 0xa3, 0xe6, 0x42, 0x6d, 0xc7, 0x5a, 0xf1, 0x63, 0x75, 0xaf, 0x92, 0x57, 0x63, 0x77, 0xfa, 0x75, 0xad, 0xa5, 0xf7, 0xb, 0xb2, 0x3c, 0x5, 0x26, 0x81, 0x73, 0xe9, 0x4e, 0x1d, 0x52, 0xd3, 0xac, 0x38, 0x49, 0x46, 0x6b, 0xdf, 0x82, 0x31, 0xd8, 0x63, 0x57, 0x8b, 0x1d, 0xed, 0x67, 0x13, 0xbd, 0x66, 0xc4, 0x7a, 0xae, 0x2f, 0x7b, 0xb5, 0xed, 0x22, 0xe2, 0x8f, 0x4d, 0xb1, 0x5d, 0x3b, 0x6a, 0xad, 0x8, 0x7c, 0x8b, 0xb8, 0x78, 0xd7, 0x76, 0xf7, 0xc6, 0x41, 0x3b, 0xdc, 0x2b, 0x55, 0xf1, 0xeb, 0xda, 0xe6, 0xe0, 0xfd, 0xf2, 0x2d, 0xbf, 0xb6, 0x7f, 0xd3, 0xe8, 0xf0, 0xb4, 0x98, 0xb1, 0x20, 0x36, 0x14, 0x1b, 0x84, 0x64, 0xcb, 0x1c, 0x36, 0x73, 0x85, 0x58, 0x87, 0x1a, 0xc7, 0x76, 0xfd, 0xa2, 0xfd, 0x21, 0xde, 0xdf, 0xf2, 0x8b, 0x88, 0x8f, 0xb0, 0x23, 0xe7, 0x6c, 0x86, 0xb5, 0x17, 0xb0, 0x1b, 0xa0, 0xf5, 0x68, 0xaf, 0x94, 0xc5, 0xaf, 0x6d, 0xdb, 0x9a, 0xee, 0xcd, 0x83, 0xa6, 0x19, 0x14, 0x68, 0x6c, 0x25, 0xe3, 0xe2, 0x9c, 0xcc, 0x17, 0x35, 0x28, 0xeb, 0x7a, 0xc1, 0x4e, 0x0, 0x2b, 0x87, 0xe8, 0x96, 0xe7, 0x68, 0x82, 0x75, 0xbc, 0x52, 0x96, 0x15, 0x6a, 0x5a, 0xae, 0x5e, 0x81, 0x6e, 0x75, 0xb, 0x2b, 0x63, 0x80, 0xda, 0x96, 0xf7, 0x79, 0x62, 0xdc, 0x2, 0xa7, 0x63, 0x37, 0x33, 0x37, 0xc1, 0xe6, 0x18, 0x3e, 0xad, 0x15, 0x51, 0x7c, 0x3b, 0x87, 0x34, 0xc0, 0xcd, 0x2b, 0x36, 0x6, 0x93, 0x78, 0xa5, 0x2a, 0xa9, 0xba, 0xf6, 0x29, 0xd9, 0x64, 0x1b, 0xdd, 0x3a, 0xe, 0xb4, 0xc5, 0x8f, 0x34, 0x47, 0x3b, 0xfa, 0x4a, 0xa, 0xbf, 0x1b, 0xdf, 0xc4, 0x98, 0x3c, 0xf4, 0xaf, 0x6d, 0x5b, 0x6, 0xff, 0x5e, 0x8a, 0x55, 0xf4, 0x35, 0x36, 0x28, 0x40, 0x27, 0x80, 0x22, 0x2f, 0xa, 0x6d, 0xe, 0xcf, 0x47, 0x3c, 0x69, 0xf7, 0xf0, 0x4a, 0x59, 0xd2, 0xf5, 0x1d, 0x4b, 0x52, 0xe4, 0x4f, 0x29, 0xec, 0x57, 0x14, 0xbd, 0x83, 0x8d, 0x3f, 0xc8, 0xd7, 0xd6, 0x27, 0x31, 0x3f, 0x47, 0x84, 0xff, 0xbc, 0xf8, 0xe6, 0xf0, 0xd5, 0x7c, 0xca, 0xd, 0xe1, 0x46, 0x8d, 0x56, 0xa0, 0xa3, 0x69, 0xb3, 0xec, 0x61, 0xfb, 0x45, 0xf8, 0xb6, 0xb9, 0xf6, 0x28, 0xd2, 0x16, 0xf7, 0x1a, 0xca, 0xe4, 0x65, 0x85, 0x9a, 0xd6, 0x47, 0x39, 0x68, 0x53, 0x94, 0x7a, 0x13, 0x9c, 0xe5, 0xd7, 0xb5, 0xd7, 0xfb, 0xf5, 0x1d, 0x53, 0xf, 0xec, 0x43, 0x64, 0xc7, 0x64, 0x74, 0x76, 0x6f, 0x4a, 0xba, 0x5e, 0x92, 0xa1, 0x52, 0x62, 0xa7, 0x1d, 0x7c, 0x87, 0xb4, 0xad, 0x23, 0x89, 0x8f, 0x77, 0x7d, 0x5c, 0xff, 0x74, 0xd4, 0x5e, 0x22, 0xec, 0x91, 0xc6, 0xe4, 0x3, 0xbe, 0x25, 0xb7, 0x47, 0x7a, 0x15, 0x25, 0xf2, 0x6b, 0xe5, 0xdc, 0x5c, 0x2b, 0x9d, 0xfe, 0xb, 0xd0, 0x8, 0x61, 0x22, 0x55, 0x7f, 0x42, 0xdb, 0x1d, 0xda, 0x22, 0xc6, 0x68, 0x21, 0xca, 0xd7, 0xf5, 0x89, 0x5f, 0xc7, 0x9d, 0x8b, 0x7e, 0xd, 0x77, 0x7e, 0xf0, 0x7b, 0x8a, 0x88, 0x91, 0x27, 0x3, 0x5a, 0xc9, 0x1, 0x9, 0x56, 0xa8, 0x6d, 0x9b, 0xcc, 0xab, 0x44, 0x49, 0xd7, 0x7, 0x17, 0xf3, 0xd9, 0xe0, 0xf3, 0xe2, 0x69, 0xaa, 0x6f, 0x57, 0xa0, 0xab, 0x1d, 0x72, 0xa1, 0xd0, 0xa, 0xad, 0xe1, 0x47, 0xde, 0x6, 0x4e, 0xf3, 0x2a, 0x55, 0x52, 0x75, 0x1d, 0x3b, 0xd2, 0x4, 0xaf, 0xf1, 0xa8, 0xcb, 0xf3, 0x76, 0xa2, 0xcb, 0x1d, 0xee, 0x43, 0xc5, 0xce, 0xc5, 0xc7, 0x2a, 0x6c, 0x2d, 0x7c, 0x4a, 0x3, 0x1c, 0xe6, 0x55, 0xb2, 0xf8, 0x75, 0xc1, 0xec, 0x7c, 0x86, 0x78, 0x51, 0x6e, 0x1e, 0x2, 0xd1, 0x36, 0x81, 0x35, 0x3f, 0x78, 0xe2, 0xd7, 0x8, 0xe2, 0x63, 0x6d, 0x1b, 0xdc, 0x79, 0x50, 0x85, 0x42, 0x82, 0xf6, 0x43, 0x3b, 0xf4, 0x51, 0xc0, 0xb8, 0x5d, 0x45, 0xad, 0x6b, 0x62, 0xb0, 0x8d, 0xbf, 0x2, 0x6d, 0x48, 0xd5, 0xb6, 0x7f, 0x86, 0x6e, 0xf4, 0x2a, 0x5d, 0x32, 0xd, 0xd9, 0x9a, 0x74, 0x43, 0xf0, 0x85, 0x49, 0x18, 0x5a, 0x81, 0x2e, 0x17, 0xd8, 0xb3, 0xbd, 0x5f, 0x55, 0x98, 0x83, 0x71, 0xf0, 0x97, 0xc1, 0xf2, 0x53, 0x72, 0x8f, 0x2e, 0xca, 0x5e, 0x8f, 0x13, 0x6f, 0xf4, 0x97, 0xe4, 0xa5, 0xce, 0xab, 0x6, 0xf1, 0xeb, 0x83, 0xde, 0x74, 0x43, 0x56, 0xa3, 0x35, 0xda, 0x5, 0x2, 0x21, 0x1b, 0x47, 0x7c, 0xbc, 0xd8, 0xf1, 0xd7, 0x5d, 0xb2, 0x36, 0x4a, 0xd0, 0xb2, 0xef, 0xb0, 0xb0, 0x42, 0x61, 0x3e, 0xc8, 0x34, 0xe6, 0x56, 0x46, 0xef, 0xce, 0x29, 0x2e, 0x36, 0x8a, 0x1b, 0x67, 0x8f, 0xa5, 0x71, 0xcc, 0xfc, 0xab, 0xb0, 0xb9, 0x57, 0x2d, 0x42, 0xa7, 0xbf, 0x1, 0xe1, 0xa3, 0xd2, 0xe8, 0x92, 0xa4, 0x71, 0xbc, 0xb1, 0x12, 0x74, 0x61, 0xdf, 0xf2, 0xa8, 0x37, 0xcd, 0x92, 0xa3, 0x78, 0x1b, 0x52, 0xd0, 0x49, 0x3c, 0x11, 0x1a, 0x61, 0x43, 0xae, 0xfd, 0xa, 0xda, 0x8d, 0xb3, 0xc6, 0xf9, 0xfe, 0xf8, 0x6c, 0x2b, 0xfe, 0x19, 0xaf, 0x5a, 0xc4, 0xaf, 0xcf, 0x2e, 0x44, 0xc2, 0xde, 0x4f, 0x87, 0x49, 0xce, 0x29, 0xd0, 0x0, 0xe1, 0xd8, 0x21, 0x5b, 0x20, 0x62, 0xce, 0xbd, 0x1e, 0x45, 0xd6, 0xd6, 0x11, 0x36, 0x38, 0x31, 0xec, 0x51, 0x59, 0xb1, 0x8a, 0x62, 0xcb, 0x7c, 0x0, 0xd9, 0x7, 0x33, 0x8d, 0x9d, 0xab, 0xa5, 0x1b, 0x73, 0x53, 0xa4, 0x9b, 0x7a, 0xfe, 0xe7, 0x39, 0x92, 0x6e, 0xc8, 0x2d, 0xcc, 0x7d, 0x3e, 0x81, 0x9f, 0xac, 0x93, 0x1b, 0x6f, 0x2d, 0x59, 0xff, 0x46, 0xbf, 0x21, 0xbb, 0xa0, 0x57, 0x4d, 0xc2, 0xd, 0x6f, 0xc6, 0x8d, 0x7f, 0x26, 0xd, 0x60, 0x35, 0x41, 0x3c, 0xc4, 0x28, 0xdb, 0x6, 0xfb, 0x9a, 0xd1, 0x23, 0x8e, 0xfd, 0xf8, 0x67, 0xfc, 0x1, 0x45, 0x3f, 0x97, 0xa2, 0x2f, 0xa, 0x53, 0x31, 0xfe, 0xcf, 0xdf, 0xc8, 0xc5, 0x67, 0x16, 0x1a, 0xe1, 0x60, 0xeb, 0xad, 0x4e, 0x89, 0x86, 0xdc, 0xe1, 0xe9, 0xc6, 0xce, 0x99, 0xbc, 0x6a, 0x13, 0x1a, 0xe0, 0x4c, 0x6e, 0xfe, 0x67, 0x93, 0x5c, 0xb4, 0x26, 0xa1, 0x83, 0x82, 0x98, 0x3c, 0xd8, 0x63, 0x83, 0x72, 0xfc, 0x54, 0x41, 0x8b, 0xaf, 0x3b, 0x1f, 0x8b, 0xb3, 0x7e, 0x1f, 0xc5, 0x5a, 0x3c, 0xd3, 0xd4, 0x35, 0x27, 0x7a, 0x1a, 0x6f, 0x10, 0x42, 0xcc, 0x14, 0xc4, 0x2c, 0xc4, 0x1a, 0x9f, 0x81, 0xe6, 0x9, 0xf8, 0x8d, 0xdf, 0x90, 0x5b, 0xdb, 0x97, 0xb7, 0x8c, 0xaa, 0x13, 0x6e, 0xbe, 0x9b, 0x93, 0x91, 0xcf, 0x34, 0x75, 0x6a, 0x50, 0xa2, 0xe3, 0x50, 0x5, 0x88, 0xd5, 0x24, 0xf4, 0x26, 0xd8, 0x1f, 0xee, 0x66, 0xfc, 0x17, 0xe8, 0x28, 0xec, 0x78, 0x6b, 0x1c, 0xb, 0xbe, 0xca, 0xb2, 0xff, 0xf1, 0x86, 0x29, 0x34, 0xc2, 0x42, 0xec, 0x77, 0x7, 0x58, 0xd2, 0xab, 0x66, 0x21, 0x1, 0x5f, 0x83, 0x26, 0x21, 0xa, 0xb4, 0xd8, 0x91, 0x70, 0xdd, 0x1d, 0xbf, 0x97, 0x6e, 0xec, 0x4a, 0xc1, 0xc4, 0x8c, 0xe7, 0xce, 0x34, 0x75, 0xa7, 0x60, 0x4d, 0xc6, 0xeb, 0xc3, 0x26, 0xb0, 0x23, 0x1c, 0x83, 0xdf, 0xb5, 0x70, 0x3f, 0x3c, 0xb, 0xda, 0x7e, 0xcd, 0x81, 0x42, 0x8c, 0x2, 0x4d, 0xd3, 0xfe, 0x63, 0x5e, 0xcf, 0x1b, 0xa6, 0xac, 0x74, 0x48, 0x2f, 0x6b, 0x54, 0xb9, 0x64, 0x1a, 0xbb, 0x2e, 0xee, 0x2f, 0x8, 0x49, 0x86, 0x15, 0xad, 0xa2, 0x60, 0xbb, 0x28, 0x8, 0xfd, 0xf0, 0x57, 0x60, 0xfc, 0xb6, 0x49, 0xd5, 0x65, 0x23, 0xdf, 0x7b, 0xcd, 0x7, 0x32, 0x7c, 0xa6, 0x85, 0x39, 0x61, 0x3e, 0xe0, 0x4b, 0xb3, 0xce, 0x3e, 0x7b, 0x2d, 0x74, 0x2c, 0xe2, 0xab, 0x88, 0xd5, 0xd0, 0x37, 0x12, 0xd, 0x90, 0x8, 0x42, 0x22, 0xe7, 0xe2, 0xc4, 0x6e, 0x4b, 0x13, 0x3c, 0x16, 0x16, 0xfd, 0xe0, 0xee, 0x2, 0xca, 0x1a, 0x2b, 0x6b, 0xac, 0xc, 0x72, 0x8a, 0xcf, 0x26, 0x7e, 0xf2, 0x41, 0xbe, 0xde, 0xc4, 0x14, 0xb2, 0x93, 0xb5, 0xf2, 0xb2, 0x5e, 0x34, 0x4d, 0xe0, 0xec, 0x47, 0xf8, 0x91, 0x3d, 0x27, 0xd, 0x30, 0xc2, 0x8d, 0xb0, 0x14, 0x49, 0xdd, 0x1b, 0x9e, 0x0, 0xd, 0x24, 0xbd, 0xc7, 0xa0, 0x84, 0xd0, 0x66, 0xde, 0xa0, 0xe1, 0x29, 0x62, 0x66, 0xf6, 0x6, 0x29, 0xac, 0x31, 0x9, 0xd4, 0x12, 0x3b, 0x4e, 0x5e, 0x43, 0xd6, 0x8e, 0xc7, 0xf8, 0x13, 0x97, 0x47, 0xbf, 0x4, 0x13, 0x79, 0xa3, 0x22, 0x49, 0x23, 0x2c, 0xb, 0xfb, 0x92, 0xe0, 0xdb, 0xe0, 0x67, 0xd0, 0x16, 0x4a, 0x8a, 0xf0, 0x3d, 0xac, 0x31, 0xf4, 0xf, 0x60, 0x3d, 0x73, 0x11, 0xaf, 0xad, 0x6, 0x80, 0x81, 0x35, 0x0, 0xfc, 0x43, 0xec, 0x9d, 0xf0, 0x7f, 0x6f, 0xf4, 0x24, 0x91, 0x74, 0x53, 0xf7, 0x1c, 0xb0, 0x3f, 0x9c, 0x43, 0xc1, 0x3a, 0x40, 0x67, 0x28, 0x2, 0xfa, 0x77, 0xe6, 0xf6, 0x1e, 0x81, 0xf5, 0x3b, 0x56, 0x3c, 0xb8, 0xb7, 0xf, 0x58, 0x93, 0x2, 0x1f, 0xd2, 0x4b, 0x91, 0x5, 0x6c, 0x1b, 0xae, 0x2b, 0x33, 0x2f, 0xfc, 0x49, 0xec, 0xd1, 0x90, 0x34, 0xc0, 0x58, 0x9, 0x45, 0xf0, 0xe1, 0x42, 0xb8, 0x1e, 0x4e, 0x1e, 0x89, 0x5f, 0x48, 0xa1, 0x80, 0x1b, 0xd2, 0x50, 0x7f, 0x80, 0x29, 0xb2, 0x12, 0xb4, 0x8c, 0x6d, 0x94, 0xc1, 0xcc, 0xb, 0x79, 0xd8, 0x4c, 0xfe, 0x34, 0xbd, 0x5c, 0x25, 0x11, 0x9a, 0xc0, 0x7c, 0xcb, 0xf6, 0x33, 0xb4, 0xa6, 0x98, 0xe3, 0xc1, 0xdc, 0x4, 0xc1, 0xff, 0x53, 0x74, 0x2b, 0x3e, 0x73, 0x7b, 0xe5, 0x2f, 0x89, 0xf0, 0x68, 0x3f, 0x8b, 0xd3, 0xdd, 0x27, 0x8f, 0x7f, 0x85, 0xfe, 0x1b, 0x7e, 0xc6, 0xfe, 0x1a, 0xfd, 0x21, 0xbc, 0xcc, 0x69, 0xf, 0xd0, 0xf, 0x33, 0x77, 0x2b, 0xf6, 0xfe, 0x2b, 0x1d, 0xfa, 0xe4, 0xd2, 0x5e, 0x65, 0x48, 0x22, 0x9c, 0xe4, 0xa9, 0x38, 0xd1, 0x77, 0xc2, 0x43, 0xd8, 0x77, 0xc0, 0x35, 0x70, 0x16, 0xff, 0x60, 0xf9, 0x70, 0xd8, 0x3, 0x7b, 0xd, 0xae, 0xcd, 0xe2, 0x95, 0xbd, 0x24, 0x92, 0x48, 0x22, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89, 0x24, 0x92, 0x48, 0x22, 0x89, 0xfc, 0xb, 0x31, 0x1b, 0x93, 0xfa, 0xac, 0xe1, 0x98, 0xc3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char mini_checkerboard_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc3, 0x0, 0x0, 0xe, 0xc3, 0x1, 0xc7, 0x6f, 0xa8, 0x64, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x7c, 0xf0, 0xe0, 0xc1, 0x7f, 0x6, 0x3c, 0x40, 0x5e, 0x5e, 0x1e, 0x9f, 0x34, 0x3, 0x13, 0x5e, 0x59, 0x22, 0xc0, 0xa8, 0x1, 0x83, 0xc1, 0x0, 0xc6, 0xff, 0xff, 0xff, 0xe3, 0x4d, 0x7, 0xf, 0x1f, 0x3e, 0xa4, 0xad, 0xb, 0x46, 0xd, 0x18, 0xc, 0x6, 0x0, 0x0, 0x6e, 0x41, 0xa, 0xba, 0x94, 0xaa, 0x47, 0x57, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x0, 0x0, 0x0, 0x0, 0x3a, 0x98, 0xa0, 0xbd, 0x0, 0x0, 0x0, 0x17, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0x0, 0x5, 0xff, 0xa1, 0x60, 0xa0, 0x4, 0x60, 0xc, 0x98, 0xc4, 0x0, 0x9, 0x0, 0x0, 0x44, 0x81, 0xef, 0x81, 0xc1, 0x26, 0x8e, 0x8, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char option_arrow_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x98, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xbd, 0x91, 0xb1, 0xd, 0xc2, 0x30, 0x10, 0x45, 0xdf, 0xd1, 0xb8, 0xf0, 0x2, 0xee, 0xdc, 0x87, 0x1, 0xd8, 0x24, 0xb5, 0xe9, 0x19, 0x87, 0x1e, 0xea, 0x6c, 0xc2, 0x0, 0xa4, 0xb5, 0xdc, 0x79, 0x1, 0x17, 0xae, 0x8e, 0x26, 0x48, 0x76, 0x14, 0x40, 0x48, 0x88, 0xdf, 0xfd, 0xf7, 0xef, 0x4b, 0x77, 0x3a, 0xf8, 0x85, 0x62, 0x8c, 0x21, 0xc6, 0x18, 0xb6, 0x32, 0x59, 0x83, 0x94, 0xd2, 0x5e, 0x55, 0x6f, 0x0, 0x22, 0x72, 0xf0, 0xde, 0xdf, 0xdb, 0x7c, 0xd7, 0x9a, 0x9c, 0xb3, 0x55, 0xd5, 0x9, 0xb0, 0x80, 0x55, 0xd5, 0x29, 0xe7, 0x6c, 0x5f, 0x16, 0x6a, 0xad, 0x67, 0x60, 0x68, 0xd0, 0xb0, 0xb0, 0x3f, 0xaa, 0x3b, 0x3a, 0xa5, 0x74, 0x51, 0xd5, 0xd0, 0xd, 0x88, 0x5c, 0xbd, 0xf7, 0xc7, 0xa7, 0xef, 0x6e, 0x30, 0xc6, 0x9c, 0x80, 0xb9, 0x41, 0xf3, 0xc2, 0xd8, 0x2c, 0x38, 0xe7, 0x8a, 0x88, 0x8c, 0x40, 0x1, 0x8a, 0x88, 0x8c, 0xce, 0xb9, 0xf2, 0x71, 0xcf, 0x77, 0x8f, 0xfb, 0x5a, 0xf, 0x28, 0x4a, 0x37, 0xff, 0x58, 0x46, 0x7b, 0x50, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x2, 0xdc, 0x4f, 0xb8, 0x9f, 0x80, 0x45, 0xf8, 0xa1, 0xf6, 0x83, 0x2f, 0xf, 0xbe, 0x3c, 0xd4, 0x46, 0x13, 0x7e, 0xc1, 0xfd, 0xe0, 0xea, 0x83, 0xff, 0x40, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xfa, 0xf9, 0x40, 0x41, 0x30, 0x7c, 0x38, 0x9f, 0x81, 0x12, 0x80, 0x69, 0x14, 0x61, 0xcb, 0x11, 0xce, 0xc5, 0xe5, 0x41, 0xc2, 0x0, 0x0, 0x95, 0x48, 0x37, 0x91, 0x1f, 0xec, 0x77, 0x5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char option_button_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x32, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3f, 0x3f, 0x5a, 0x5a, 0x5a, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x59, 0x59, 0x59, 0x2a, 0x2a, 0x30, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x27, 0x35, 0x35, 0x35, 0x4a, 0x4a, 0x4a, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x56, 0x56, 0x56, 0x62, 0x62, 0x62, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x48, 0x48, 0x48, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x54, 0x54, 0x54, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x49, 0x49, 0x49, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x39, 0x39, 0x39, 0x47, 0x47, 0x47, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x46, 0x46, 0x46, 0xff, 0xff, 0xff, 0xbd, 0x3f, 0x83, 0xbb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x65, 0xb5, 0xdd, 0x88, 0x9f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0xb, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0xd9, 0x56, 0xc2, 0x30, 0x10, 0x80, 0x61, 0xd6, 0xa2, 0xa8, 0x6c, 0x75, 0xdf, 0x10, 0x54, 0xa8, 0x82, 0x74, 0xd2, 0x4a, 0x49, 0x5b, 0xa4, 0xb5, 0x5a, 0x44, 0x10, 0x5c, 0xd0, 0xaa, 0x80, 0x8a, 0xcb, 0xfb, 0x3f, 0x83, 0x21, 0x24, 0x1c, 0x8e, 0x5e, 0xe8, 0x77, 0xfd, 0x9f, 0x93, 0x99, 0x89, 0xcf, 0x1f, 0x8, 0x86, 0xc2, 0x42, 0x84, 0x10, 0x66, 0x66, 0xa3, 0x73, 0xf3, 0xbe, 0x9f, 0x2, 0xb, 0xb1, 0x78, 0x22, 0x99, 0x12, 0x45, 0x71, 0x71, 0x69, 0x79, 0x25, 0xea, 0xff, 0x15, 0x4, 0x63, 0xab, 0x6b, 0x7b, 0xcc, 0x7e, 0x2e, 0x2f, 0x1d, 0x30, 0x87, 0x52, 0x21, 0xbf, 0xbe, 0x41, 0x82, 0x50, 0x7c, 0xb3, 0x78, 0x54, 0x1a, 0x93, 0x1, 0x29, 0x2a, 0x73, 0xac, 0x94, 0x35, 0x6d, 0x8b, 0x4, 0xe1, 0x84, 0x5c, 0xe2, 0xe4, 0xa, 0xd6, 0xb, 0x8c, 0xa1, 0x2b, 0xd8, 0x54, 0x48, 0x20, 0x24, 0xab, 0x27, 0x5c, 0xb5, 0x2, 0x39, 0x89, 0xa9, 0x19, 0x2a, 0x58, 0xa3, 0x20, 0x92, 0xb2, 0x4f, 0x39, 0xdb, 0x1, 0xe3, 0x8c, 0xa9, 0x9d, 0xbb, 0x60, 0x3a, 0xa3, 0x40, 0xac, 0x5f, 0x70, 0xf5, 0xe9, 0xc0, 0x20, 0x1, 0xd0, 0xa0, 0x71, 0xc9, 0x35, 0xca, 0x4d, 0x75, 0x6a, 0x86, 0xd6, 0x15, 0xa6, 0x4f, 0xb4, 0x3b, 0x5c, 0x1b, 0xa1, 0xeb, 0x1b, 0x46, 0xbf, 0x5, 0xed, 0xe, 0xd1, 0x21, 0xbb, 0xf7, 0x5c, 0xf7, 0xc1, 0xf2, 0x26, 0x6b, 0x7a, 0x4d, 0xeb, 0xd1, 0xa2, 0x6b, 0x3e, 0x3d, 0x73, 0xc5, 0x5e, 0x1f, 0x7b, 0xc, 0xe0, 0xc1, 0xcb, 0xab, 0x49, 0xf, 0xb5, 0xdd, 0x79, 0x63, 0x86, 0xbd, 0x77, 0xd, 0x33, 0xad, 0x41, 0xff, 0xe3, 0x33, 0x4d, 0x4f, 0xbd, 0x93, 0x19, 0x7e, 0x8d, 0xd9, 0x0, 0xee, 0x64, 0x6, 0xd7, 0x41, 0xd9, 0xdd, 0xff, 0x7c, 0xd6, 0x5f, 0xdf, 0xfd, 0xd, 0xbf, 0xaa, 0x55, 0xdf, 0x7c, 0xb2, 0x44, 0x90, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x2f, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3f, 0x3f, 0x5a, 0x5a, 0x5a, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x59, 0x59, 0x59, 0x2a, 0x2a, 0x30, 0x4b, 0x4b, 0x4b, 0x22, 0x22, 0x27, 0x35, 0x35, 0x35, 0x4a, 0x4a, 0x4a, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x56, 0x56, 0x56, 0x62, 0x62, 0x62, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x48, 0x48, 0x48, 0x44, 0x44, 0x44, 0x43, 0x43, 0x43, 0x54, 0x54, 0x54, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x52, 0x52, 0x52, 0x42, 0x42, 0x42, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x51, 0x51, 0x51, 0x40, 0x40, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4f, 0x4f, 0x4f, 0x3f, 0x3f, 0x3f, 0x4d, 0x4d, 0x4d, 0x3e, 0x3e, 0x3e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4c, 0x4c, 0x4c, 0x3d, 0x3d, 0x3d, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4a, 0x4a, 0x4a, 0x3b, 0x3b, 0x3b, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x49, 0x49, 0x49, 0x3a, 0x3a, 0x3a, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x39, 0x39, 0x39, 0x47, 0x47, 0x47, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x46, 0x46, 0x46, 0xd3, 0xa7, 0xd4, 0x88, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xec, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x8e, 0x5, 0x4e, 0x0, 0x31, 0x10, 0x45, 0xff, 0xef, 0x56, 0xc2, 0xe2, 0xee, 0x4e, 0x3c, 0xc8, 0xd, 0xb8, 0x38, 0xa7, 0xc0, 0xdd, 0xdd, 0x5d, 0xbb, 0x94, 0x4c, 0xd2, 0xc1, 0xdf, 0x4a, 0x47, 0x5e, 0x27, 0xc3, 0xc, 0x80, 0x64, 0x24, 0xb8, 0xc7, 0x4f, 0x2c, 0x6b, 0xd5, 0x90, 0xff, 0xdd, 0x23, 0x7e, 0xc1, 0xa2, 0xb6, 0x64, 0xad, 0x26, 0x82, 0xc6, 0xef, 0x45, 0xbc, 0xe3, 0x1, 0x2c, 0x69, 0x9b, 0xc8, 0x7f, 0x5, 0x36, 0x1e, 0x41, 0x84, 0xd6, 0x4, 0x25, 0x90, 0xb7, 0x39, 0x6c, 0x4c, 0x2f, 0xbe, 0x68, 0xdf, 0x13, 0xa1, 0x9e, 0xc8, 0xa4, 0xb7, 0xe7, 0x47, 0x93, 0x63, 0x1b, 0xf9, 0xdc, 0x8, 0x88, 0x60, 0xbf, 0x4, 0xff, 0xd2, 0x56, 0x93, 0xe3, 0xb7, 0xb2, 0xf6, 0x2c, 0x36, 0x1, 0x16, 0xf4, 0x5f, 0x42, 0xc4, 0x17, 0x8f, 0xb5, 0xc0, 0xa5, 0x8, 0x30, 0x5f, 0xc2, 0x5d, 0xcf, 0xc9, 0xd, 0x74, 0x87, 0x8b, 0x5e, 0x56, 0x22, 0x24, 0xf7, 0x6d, 0xc2, 0xd1, 0x80, 0x26, 0x27, 0x5d, 0x5b, 0x67, 0x7d, 0x2f, 0x80, 0x4d, 0xc9, 0x7f, 0x9, 0x63, 0xa7, 0x61, 0x23, 0xc7, 0x74, 0x3d, 0xf, 0xae, 0x41, 0x84, 0x6f, 0x13, 0xe6, 0x26, 0xfa, 0x36, 0x46, 0x73, 0xbc, 0xba, 0x3b, 0xd6, 0xca, 0x8, 0xd0, 0xd6, 0x36, 0x4e, 0x35, 0xeb, 0xad, 0xd7, 0xb0, 0x60, 0x72, 0xdc, 0xda, 0x9c, 0x2, 0x67, 0x76, 0x64, 0x82, 0x99, 0x9b, 0xb6, 0x80, 0xb0, 0x7e, 0x8d, 0xf6, 0x5a, 0xdd, 0xe1, 0xb5, 0xba, 0xba, 0xb1, 0x0, 0xcd, 0xc7, 0x50, 0x23, 0xeb, 0xfb, 0x7f, 0xb4, 0xc8, 0x22, 0x18, 0xdd, 0x0, 0xd5, 0xec, 0x4e, 0x53, 0xc6, 0x18, 0x44, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char option_button_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xb4, 0x50, 0x4c, 0x54, 0x45, 0x95, 0xa9, 0xb0, 0x92, 0xa7, 0xae, 0x8e, 0xa2, 0xa9, 0x8a, 0x9d, 0xa4, 0x85, 0x98, 0x9f, 0x80, 0x93, 0x9b, 0x7b, 0x8f, 0x96, 0x77, 0x8a, 0x92, 0x72, 0x86, 0x8c, 0x6e, 0x80, 0x88, 0x69, 0x7c, 0x84, 0x64, 0x77, 0x7f, 0x60, 0x72, 0x7a, 0x5b, 0x6e, 0x75, 0x56, 0x69, 0x71, 0xc8, 0xe3, 0xe7, 0xc8, 0xe2, 0xe7, 0xca, 0xe3, 0xe7, 0xce, 0xe6, 0xe9, 0xce, 0xe6, 0xea, 0xd0, 0xe6, 0xe9, 0xce, 0xe5, 0xea, 0xd0, 0xe6, 0xea, 0xce, 0xe5, 0xe9, 0xd0, 0xe5, 0xe9, 0xd3, 0xe7, 0xeb, 0xd4, 0xe7, 0xeb, 0xd9, 0xea, 0xed, 0xd7, 0xe9, 0xed, 0xd7, 0xea, 0xed, 0xdc, 0xec, 0xef, 0xdc, 0xeb, 0xef, 0xe0, 0xed, 0xf1, 0xdf, 0xee, 0xf1, 0xdf, 0xed, 0xf1, 0xe0, 0xee, 0xf1, 0xe3, 0xf0, 0xf2, 0xe2, 0xef, 0xf2, 0xe3, 0xef, 0xf2, 0xe6, 0xf1, 0xf3, 0xe8, 0xf2, 0xf5, 0xe8, 0xf3, 0xf4, 0xe8, 0xf2, 0xf4, 0xe8, 0xf3, 0xf5, 0xd6, 0x5a, 0x5b, 0xd4, 0x57, 0x58, 0xe5, 0x89, 0x89, 0xd5, 0x57, 0x59, 0xd5, 0x58, 0x59, 0xd5, 0x59, 0x5a, 0xd6, 0x59, 0x5a, 0xd6, 0x5a, 0x5c, 0xd7, 0x5b, 0x5c, 0xd7, 0x5b, 0x5d, 0xd8, 0x5c, 0x5d, 0xd8, 0x5c, 0x5e, 0xd8, 0x5d, 0x5f, 0xd9, 0x5d, 0x5f, 0xe8, 0x6c, 0x6e, 0xff, 0xff, 0xff, 0xa1, 0xe, 0x37, 0x8c, 0x0, 0x0, 0x0, 0x2c, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xac, 0x80, 0x68, 0x47, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x3b, 0x39, 0xe, 0xf4, 0x6c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xa3, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x5d, 0xce, 0xdb, 0x16, 0x42, 0x60, 0x18, 0x84, 0xe1, 0x4f, 0x8, 0x65, 0x57, 0x2a, 0x45, 0xd9, 0x15, 0xf9, 0xa3, 0x89, 0x28, 0xea, 0xfe, 0x2f, 0x2c, 0x4e, 0x2c, 0x79, 0xd6, 0xbc, 0xe7, 0x43, 0x34, 0xc5, 0xe5, 0x7f, 0x38, 0x9a, 0xdd, 0x31, 0x72, 0x9f, 0x11, 0xff, 0x80, 0x61, 0x18, 0xa6, 0x69, 0xac, 0xba, 0x50, 0xf0, 0x24, 0x14, 0x58, 0x5b, 0x9b, 0xed, 0xce, 0xb6, 0x6d, 0x6b, 0x8f, 0x42, 0x20, 0xb1, 0xc4, 0xc1, 0x71, 0xe, 0x7d, 0x8e, 0x83, 0x52, 0xa4, 0xf9, 0x13, 0xae, 0x7b, 0x74, 0x7b, 0xa7, 0x13, 0x9e, 0x73, 0x92, 0x72, 0x78, 0xbe, 0xef, 0x75, 0x7c, 0xcf, 0x47, 0x2e, 0x91, 0x5c, 0x21, 0x8, 0xc2, 0x20, 0x8c, 0x82, 0x73, 0x18, 0xa1, 0x92, 0x49, 0xa9, 0x71, 0x89, 0xe3, 0x38, 0x49, 0xba, 0x25, 0xa8, 0x15, 0x5a, 0xbc, 0x70, 0x1d, 0xe0, 0xb5, 0xa0, 0xe5, 0x1b, 0x69, 0xca, 0xd8, 0x8d, 0x31, 0x96, 0x65, 0x68, 0x96, 0xa4, 0x36, 0x60, 0x3, 0x34, 0x2a, 0x69, 0xed, 0xf8, 0x7a, 0xab, 0x91, 0xfe, 0xf9, 0x8e, 0x7c, 0x74, 0xd2, 0x27, 0x7e, 0x7e, 0x46, 0x20, 0x17, 0xe, 0x2d, 0x4e, 0x9, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xb1, 0x50, 0x4c, 0x54, 0x45, 0x95, 0xa9, 0xb0, 0x92, 0xa7, 0xae, 0x8e, 0xa2, 0xa9, 0x8a, 0x9d, 0xa4, 0x85, 0x98, 0x9f, 0x80, 0x93, 0x9b, 0x7b, 0x8f, 0x96, 0x77, 0x8a, 0x92, 0x72, 0x86, 0x8c, 0x6e, 0x80, 0x88, 0x69, 0x7c, 0x84, 0x64, 0x77, 0x7f, 0x60, 0x72, 0x7a, 0x5b, 0x6e, 0x75, 0x56, 0x69, 0x71, 0xc8, 0xe3, 0xe7, 0xc8, 0xe2, 0xe7, 0xca, 0xe3, 0xe7, 0xce, 0xe6, 0xe9, 0xce, 0xe6, 0xea, 0xd0, 0xe6, 0xe9, 0xce, 0xe5, 0xea, 0xd0, 0xe6, 0xea, 0xce, 0xe5, 0xe9, 0xd0, 0xe5, 0xe9, 0xd3, 0xe7, 0xeb, 0xd4, 0xe7, 0xeb, 0xd9, 0xea, 0xed, 0xd7, 0xe9, 0xed, 0xd7, 0xea, 0xed, 0xdc, 0xec, 0xef, 0xdc, 0xeb, 0xef, 0xe0, 0xed, 0xf1, 0xdf, 0xee, 0xf1, 0xdf, 0xed, 0xf1, 0xe0, 0xee, 0xf1, 0xe3, 0xf0, 0xf2, 0xe2, 0xef, 0xf2, 0xe3, 0xef, 0xf2, 0xe6, 0xf1, 0xf3, 0xe8, 0xf2, 0xf5, 0xe8, 0xf3, 0xf4, 0xe8, 0xf2, 0xf4, 0xe8, 0xf3, 0xf5, 0xd6, 0x5a, 0x5b, 0xd4, 0x57, 0x58, 0xe5, 0x89, 0x89, 0xd5, 0x57, 0x59, 0xd5, 0x58, 0x59, 0xd5, 0x59, 0x5a, 0xd6, 0x59, 0x5a, 0xd6, 0x5a, 0x5c, 0xd7, 0x5b, 0x5c, 0xd7, 0x5b, 0x5d, 0xd8, 0x5c, 0x5d, 0xd8, 0x5c, 0x5e, 0xd8, 0x5d, 0x5f, 0xd9, 0x5d, 0x5f, 0xe8, 0x6c, 0x6e, 0x20, 0x6, 0x32, 0x78, 0x0, 0x0, 0x0, 0x2c, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0xac, 0x80, 0x68, 0x47, 0x0, 0x0, 0x0, 0x72, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xc8, 0xc1, 0x8d, 0xc2, 0x30, 0x18, 0x6, 0xd1, 0x99, 0xdf, 0x8e, 0x7c, 0x59, 0x6d, 0xb, 0x14, 0x40, 0xff, 0xa5, 0x50, 0x0, 0x6d, 0x4, 0xe4, 0xf, 0x59, 0x8, 0x42, 0xde, 0xf1, 0x35, 0xce, 0xd0, 0x2b, 0xbf, 0x6e, 0x5d, 0xe5, 0x10, 0xbb, 0x95, 0x3b, 0x48, 0x2a, 0xe4, 0xd2, 0xec, 0x9a, 0xe6, 0x2, 0xcf, 0xd, 0x56, 0x30, 0x24, 0x48, 0x6, 0xb8, 0x82, 0xc2, 0x0, 0xd6, 0x3b, 0xf6, 0x6a, 0x12, 0xc0, 0xc8, 0x6e, 0x77, 0x3c, 0xa, 0xa3, 0xb3, 0x4d, 0x19, 0x76, 0xa5, 0xb, 0x12, 0x1b, 0xb8, 0x82, 0xc6, 0x22, 0x7c, 0x42, 0xc4, 0x40, 0x41, 0x59, 0x8a, 0x42, 0x80, 0x39, 0xc1, 0xae, 0x6c, 0x7c, 0xb9, 0xe2, 0x8f, 0x43, 0xf4, 0x9f, 0xb3, 0x17, 0x98, 0xa8, 0x1a, 0xb6, 0xa7, 0xd9, 0xa6, 0x4e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char option_button_hover_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x44, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x5f, 0x5a, 0x6b, 0x2a, 0x2a, 0x30, 0x56, 0x53, 0x64, 0x22, 0x22, 0x27, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x67, 0x63, 0x76, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5a, 0x56, 0x65, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x5b, 0x57, 0x66, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x43, 0x40, 0x4c, 0x54, 0x50, 0x5f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x4f, 0x5f, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x5f, 0x5a, 0x6c, 0xff, 0xff, 0xff, 0xd1, 0x85, 0xc5, 0x5, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6b, 0x52, 0x65, 0xa5, 0x98, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0x10, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0xd9, 0x52, 0xc2, 0x30, 0x14, 0x80, 0x61, 0xd6, 0xa2, 0xa8, 0x6c, 0x75, 0xdf, 0x77, 0xa8, 0xa2, 0x70, 0xd2, 0x4a, 0x25, 0x6d, 0x81, 0x62, 0xa1, 0x88, 0x20, 0x6e, 0xc5, 0xaa, 0x80, 0xfb, 0xfa, 0xfe, 0xf, 0x60, 0x49, 0x13, 0x86, 0xd1, 0xb, 0xfd, 0x6e, 0xf3, 0xcf, 0xe4, 0x24, 0xc7, 0xe3, 0xf5, 0xf9, 0x3, 0x41, 0x2e, 0xe4, 0xe0, 0x46, 0x46, 0xc3, 0x63, 0xe3, 0x9e, 0x9f, 0x7c, 0x13, 0x91, 0x68, 0x2c, 0x9e, 0xe0, 0x79, 0x7e, 0x72, 0x6a, 0x7a, 0x26, 0xec, 0xfd, 0x15, 0xf8, 0x23, 0xb3, 0x73, 0x9b, 0x5b, 0xae, 0xed, 0x64, 0x4a, 0xd8, 0xa1, 0x76, 0x85, 0x74, 0x6a, 0x7e, 0xc1, 0x9, 0x2, 0xd1, 0xc5, 0xbd, 0xfd, 0x8c, 0x2b, 0xb, 0x48, 0x94, 0xa8, 0x3, 0x31, 0x27, 0xcb, 0x4b, 0x4e, 0x10, 0x8c, 0x1d, 0xb2, 0xf3, 0x4c, 0x36, 0x8f, 0x95, 0x34, 0xa5, 0x2a, 0x22, 0xd6, 0x44, 0x27, 0xe0, 0xe2, 0x85, 0x22, 0x53, 0xc8, 0x43, 0x52, 0xa0, 0x4a, 0xaa, 0x4, 0x7a, 0x3f, 0x8, 0x25, 0xca, 0x47, 0x4c, 0xd9, 0x0, 0xb5, 0x42, 0x95, 0xaa, 0x26, 0x68, 0x46, 0x3f, 0xe0, 0x6b, 0xc7, 0x4c, 0x6d, 0x38, 0x50, 0x9d, 0x0, 0x48, 0x50, 0x3f, 0x61, 0xea, 0xb9, 0x86, 0x34, 0x34, 0x43, 0xf3, 0x14, 0x93, 0x2b, 0x5a, 0x67, 0x4c, 0xb, 0xa1, 0xf3, 0xb, 0x4a, 0xb9, 0x4, 0xf9, 0xa, 0x91, 0x21, 0xad, 0x36, 0x63, 0x5d, 0xeb, 0xf6, 0xe0, 0x99, 0x76, 0x43, 0xbf, 0xd1, 0xc9, 0x33, 0xad, 0xf6, 0x2d, 0x75, 0xd7, 0xe9, 0x62, 0x9b, 0x2, 0xdc, 0xbb, 0x7f, 0xd0, 0xc8, 0x47, 0x2d, 0x3f, 0x3e, 0x3d, 0xbb, 0x5e, 0x3a, 0xaf, 0x32, 0xa6, 0x9a, 0xbd, 0xee, 0xdb, 0xfb, 0xa, 0xf9, 0xea, 0xd5, 0xb5, 0x8f, 0x4f, 0xd7, 0x17, 0x80, 0x39, 0x98, 0xc1, 0x34, 0xd0, 0xfa, 0xc6, 0x7f, 0x96, 0xf5, 0xd7, 0xba, 0xbf, 0x1, 0xfe, 0x22, 0x58, 0x7c, 0xf4, 0xd2, 0xd1, 0x68, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x40, 0x4b, 0x5f, 0x5a, 0x6c, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x5f, 0x5a, 0x6b, 0x2a, 0x2a, 0x30, 0x56, 0x53, 0x64, 0x22, 0x22, 0x27, 0x3e, 0x3b, 0x46, 0x57, 0x53, 0x63, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x5b, 0x57, 0x68, 0x5a, 0x56, 0x67, 0x67, 0x63, 0x76, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x4d, 0x4a, 0x57, 0x49, 0x46, 0x52, 0x48, 0x45, 0x51, 0x5a, 0x56, 0x65, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x5b, 0x57, 0x66, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x59, 0x55, 0x64, 0x47, 0x44, 0x50, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x58, 0x54, 0x64, 0x46, 0x43, 0x50, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x56, 0x53, 0x63, 0x45, 0x42, 0x4f, 0x56, 0x53, 0x62, 0x45, 0x42, 0x4e, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x55, 0x51, 0x62, 0x44, 0x41, 0x4e, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x55, 0x51, 0x60, 0x44, 0x41, 0x4d, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x43, 0x40, 0x4c, 0x54, 0x50, 0x5f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x47, 0x43, 0x51, 0x43, 0x3f, 0x4d, 0x42, 0x3f, 0x4c, 0x53, 0x4f, 0x5f, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x53, 0x50, 0x5f, 0x53, 0x4f, 0x5e, 0x5f, 0x5a, 0x6c, 0xd3, 0x26, 0x54, 0x35, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe5, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x85, 0x91, 0x43, 0x62, 0xc5, 0x60, 0x18, 0x45, 0xef, 0x8d, 0x51, 0xdb, 0xee, 0x46, 0xca, 0x6d, 0x77, 0x58, 0xce, 0x6b, 0xdb, 0x7c, 0x8a, 0xad, 0xea, 0x44, 0x1f, 0x4e, 0x92, 0x1f, 0x4c, 0x0, 0xe0, 0x9, 0x61, 0xf0, 0x89, 0x32, 0x12, 0xcd, 0xd4, 0x8, 0xef, 0x1f, 0x35, 0x54, 0xa0, 0x68, 0x1a, 0x34, 0x89, 0x8, 0x86, 0xa4, 0xd, 0x57, 0xb4, 0xdf, 0x79, 0x5, 0x89, 0x94, 0xba, 0xf9, 0xb3, 0xc0, 0xce, 0xeb, 0xf0, 0x17, 0x1c, 0xab, 0x11, 0x9, 0x1a, 0xf9, 0x96, 0x84, 0x5d, 0x5e, 0x43, 0x15, 0x7, 0x2e, 0x42, 0x41, 0x51, 0xd3, 0xbe, 0x67, 0xd5, 0x6b, 0x42, 0x3a, 0x38, 0x9b, 0xf5, 0x2e, 0x20, 0xfa, 0x5, 0x33, 0x41, 0x69, 0xf4, 0xeb, 0x49, 0x6c, 0x19, 0xe6, 0xbd, 0xdd, 0xd, 0x48, 0xa0, 0x92, 0xb, 0x36, 0x72, 0x6a, 0x26, 0xf0, 0x14, 0xa, 0x10, 0x72, 0xe1, 0x7d, 0xf4, 0xf6, 0x35, 0x1b, 0xc3, 0xe3, 0x18, 0x9d, 0x50, 0xf0, 0xe4, 0xc2, 0x17, 0xae, 0x27, 0xd3, 0xe4, 0x6e, 0xe8, 0xf8, 0x7e, 0xbc, 0x1, 0x48, 0x9e, 0x57, 0xf8, 0xc5, 0xfc, 0xbd, 0x7a, 0x98, 0xc4, 0x94, 0x47, 0xbf, 0xe4, 0xce, 0x48, 0x8, 0x6e, 0x69, 0x91, 0x63, 0x47, 0x73, 0x49, 0xbc, 0x77, 0x3e, 0xd7, 0x4b, 0x3b, 0x12, 0x36, 0x16, 0xb3, 0x85, 0x6a, 0x68, 0xce, 0x39, 0x62, 0xc6, 0xba, 0x3d, 0x8d, 0xe7, 0x91, 0x20, 0xac, 0xad, 0xa6, 0xc2, 0xe, 0x6, 0xcc, 0x74, 0xc, 0x2d, 0xe7, 0xf9, 0x55, 0x2, 0x28, 0x94, 0x37, 0xab, 0xee, 0xa1, 0xcc, 0xbf, 0xdb, 0xed, 0x3, 0x70, 0xe6, 0x4f, 0x4a, 0xc3, 0xed, 0xed, 0xf3, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char option_button_normal_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x44, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0xff, 0xff, 0xff, 0xd7, 0xc8, 0xfe, 0x88, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6b, 0x52, 0x65, 0xa5, 0x98, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x1, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0xd7, 0x56, 0xc2, 0x40, 0x10, 0x80, 0x61, 0x6a, 0x50, 0x54, 0x5a, 0xec, 0xbd, 0x43, 0x14, 0x85, 0xdd, 0x44, 0xa2, 0x6c, 0x12, 0x20, 0x18, 0xd, 0x22, 0x8, 0x16, 0x34, 0x16, 0xc0, 0x5e, 0xde, 0xff, 0x1, 0x5c, 0x36, 0xb3, 0x1c, 0x8e, 0x5e, 0xe8, 0x77, 0xfd, 0x9f, 0xb3, 0x33, 0xb3, 0x1e, 0xaf, 0xcf, 0x1f, 0x8, 0xa, 0x21, 0x4a, 0x18, 0x1a, 0xe, 0x8f, 0x8c, 0x7a, 0x7e, 0xf2, 0x8d, 0x45, 0xa2, 0xb1, 0x78, 0x42, 0x14, 0xc5, 0xf1, 0x89, 0xc9, 0xa9, 0xb0, 0xf7, 0x57, 0xe0, 0x8f, 0x4c, 0xcf, 0xac, 0x6f, 0xb8, 0x36, 0x93, 0x29, 0x69, 0xb, 0x6c, 0x4b, 0xe9, 0xd4, 0xec, 0x1c, 0xd, 0x2, 0xd1, 0xf9, 0x9d, 0xdd, 0x8c, 0x2b, 0x8b, 0xb0, 0xac, 0x80, 0x3d, 0x39, 0xa7, 0xaa, 0xb, 0x34, 0x8, 0xc6, 0xb2, 0x99, 0x7d, 0x70, 0x90, 0x27, 0x5a, 0x1a, 0xe8, 0x9a, 0x4c, 0xc, 0x99, 0x6, 0x42, 0xbc, 0x50, 0xe4, 0xa, 0x79, 0x94, 0x94, 0x40, 0x49, 0x57, 0x90, 0xd9, 0xb, 0x42, 0x89, 0xf2, 0x21, 0x57, 0xb6, 0x90, 0x7e, 0x4, 0x4a, 0xc7, 0x36, 0x32, 0xac, 0x5e, 0x20, 0x56, 0x4e, 0xb8, 0xca, 0x60, 0xa0, 0xd3, 0x0, 0xb1, 0xa0, 0x7a, 0xca, 0x55, 0x73, 0x35, 0x65, 0x60, 0x86, 0xfa, 0x19, 0x61, 0x4f, 0x34, 0x9a, 0x5c, 0x3, 0xe3, 0xf3, 0xb, 0xa0, 0x5d, 0x22, 0xf5, 0xa, 0xb3, 0x21, 0x5b, 0xd7, 0x5c, 0xeb, 0xc6, 0x74, 0xfa, 0x6b, 0x3a, 0x35, 0xf3, 0xd6, 0x64, 0x6b, 0xde, 0xdd, 0x73, 0xf, 0xed, 0xe, 0x71, 0x0, 0x22, 0xdd, 0xc7, 0x27, 0x83, 0x1d, 0x6a, 0xb1, 0xf9, 0xc, 0x5e, 0xda, 0xaf, 0x2a, 0x1, 0xf5, 0x6e, 0xe7, 0xed, 0x7d, 0x89, 0x9d, 0x7a, 0x79, 0xe5, 0xe3, 0xd3, 0xf5, 0x85, 0x90, 0xdd, 0x9f, 0xc1, 0xb6, 0xf0, 0xea, 0xda, 0x7f, 0x3e, 0xeb, 0xaf, 0xef, 0xfe, 0x6, 0x1a, 0x96, 0x59, 0x89, 0x91, 0xf7, 0xf1, 0x7b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x41, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x56, 0x52, 0x60, 0x2a, 0x2a, 0x30, 0x47, 0x44, 0x52, 0x22, 0x22, 0x27, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x5d, 0x5a, 0x6a, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x46, 0x42, 0x4f, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x4e, 0x4b, 0x58, 0x8, 0xd9, 0x10, 0xcb, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe7, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0x91, 0x53, 0x62, 0x5, 0x41, 0x14, 0x44, 0xab, 0x46, 0xb1, 0x6d, 0x67, 0x3, 0x59, 0x44, 0x16, 0x9e, 0xdf, 0xe8, 0x2f, 0xb6, 0xcd, 0xe7, 0x61, 0xe3, 0x3e, 0x4e, 0xb5, 0x2e, 0x4e, 0xdb, 0xa3, 0x11, 0x80, 0xc4, 0x51, 0xc6, 0x3f, 0x5a, 0xe5, 0xb1, 0x4f, 0x8, 0xd5, 0xff, 0x15, 0xd1, 0x26, 0xba, 0x7d, 0xbd, 0xec, 0xa3, 0x75, 0x94, 0x24, 0x11, 0xbb, 0xe1, 0x2f, 0x1f, 0xe0, 0x91, 0xde, 0x8, 0xf3, 0x1, 0xe, 0x3d, 0x42, 0x1, 0xe3, 0x49, 0xf, 0x1a, 0xc0, 0xb7, 0xb5, 0x47, 0x92, 0x52, 0xb7, 0x3b, 0x79, 0xa7, 0x80, 0x21, 0xc2, 0x2a, 0xa9, 0x15, 0x8b, 0x8e, 0x1c, 0x2e, 0x64, 0x71, 0x4, 0xd0, 0x5b, 0x34, 0x80, 0xa0, 0x34, 0x29, 0xab, 0xd5, 0x7a, 0xfb, 0x5e, 0xc2, 0x51, 0xc0, 0x3, 0x83, 0x6, 0x10, 0xa2, 0xa1, 0x62, 0x1f, 0xf0, 0xae, 0x0, 0x38, 0xd, 0xe0, 0x67, 0xfe, 0xe9, 0xb, 0x72, 0x86, 0xb7, 0x5, 0x46, 0xa, 0x48, 0xfc, 0xa6, 0x15, 0x1e, 0x96, 0xc5, 0x79, 0x99, 0xbe, 0x78, 0x59, 0x2c, 0x1, 0x5e, 0x92, 0x34, 0x6d, 0xb1, 0xf9, 0xda, 0x75, 0x66, 0x6d, 0xfa, 0xf3, 0x5, 0x7f, 0x58, 0x3, 0x8d, 0x15, 0xc8, 0x85, 0xf3, 0xd, 0x6b, 0x1f, 0xdf, 0x6e, 0x8c, 0x33, 0xd4, 0xc0, 0xce, 0xd6, 0xa8, 0x0, 0xd5, 0x20, 0xbc, 0xb5, 0xf6, 0xc2, 0x68, 0xb6, 0xf4, 0x8d, 0x6, 0x9c, 0xc3, 0x6d, 0x5a, 0x60, 0xf, 0x53, 0x7d, 0x72, 0x86, 0x6a, 0xf4, 0xf1, 0xed, 0x1, 0x74, 0x5a, 0x3f, 0xab, 0x94, 0xee, 0x3f, 0x7a, 0x64, 0x11, 0x8a, 0x6e, 0x0, 0x80, 0xdd, 0x4f, 0x5c, 0xe, 0xd7, 0x26, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char option_button_pressed_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x4d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0xff, 0xff, 0xff, 0x2, 0x4e, 0xff, 0xf1, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6e, 0x22, 0xf, 0x51, 0x17, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x8d, 0xd1, 0x57, 0x53, 0xc2, 0x40, 0x10, 0xc0, 0x71, 0x6a, 0x50, 0x54, 0x5a, 0xec, 0xbd, 0x43, 0x14, 0xf5, 0x2e, 0x91, 0xa8, 0x5c, 0x12, 0x20, 0x18, 0xd, 0x22, 0x88, 0xd, 0x8d, 0xd, 0xb0, 0xd7, 0xef, 0xff, 0xea, 0x71, 0xd9, 0x63, 0x18, 0x7d, 0xd0, 0xdf, 0xf3, 0x7f, 0xe6, 0x76, 0xf7, 0x3c, 0x5e, 0x9f, 0x3f, 0x10, 0x14, 0x42, 0x94, 0xd0, 0xd3, 0x1b, 0xee, 0xeb, 0xf7, 0xfc, 0xe4, 0x1b, 0x88, 0x44, 0x63, 0xf1, 0x84, 0x28, 0x8a, 0x83, 0x43, 0xc3, 0x23, 0x61, 0xef, 0xaf, 0xc0, 0x1f, 0x19, 0x1d, 0x5b, 0x5c, 0x72, 0x2d, 0x27, 0x53, 0xd2, 0xa, 0x58, 0x95, 0xd2, 0xa9, 0xf1, 0x9, 0x1a, 0x4, 0xa2, 0x93, 0x6b, 0xeb, 0x60, 0x3, 0x61, 0x59, 0x1, 0x9b, 0x72, 0x46, 0x55, 0xa7, 0x68, 0x10, 0x8c, 0x6d, 0x6d, 0x73, 0x3b, 0x59, 0xa2, 0xa5, 0x81, 0xae, 0xc9, 0xc4, 0x90, 0x69, 0x20, 0xc4, 0x73, 0x79, 0x2e, 0x97, 0x45, 0x49, 0x9, 0x14, 0x74, 0x5, 0x99, 0xed, 0x20, 0x94, 0x28, 0xee, 0x72, 0x45, 0xb, 0xe9, 0x7b, 0xa0, 0xb0, 0x6f, 0x23, 0xc3, 0x6a, 0x7, 0x62, 0xe9, 0x80, 0x2b, 0x75, 0x7, 0x3a, 0xd, 0x10, 0xb, 0xca, 0x87, 0x5c, 0x39, 0x53, 0x51, 0xba, 0x66, 0xa8, 0x1e, 0x11, 0xf6, 0x44, 0xed, 0x98, 0xab, 0x61, 0x7c, 0x72, 0xa, 0xb4, 0x33, 0xa4, 0x9e, 0x63, 0x36, 0x64, 0xfd, 0x82, 0xab, 0x5f, 0x9a, 0x4e, 0x67, 0x4d, 0xa7, 0x62, 0x5e, 0x99, 0x6c, 0xcd, 0xeb, 0x9b, 0x5b, 0x70, 0xd7, 0x68, 0x12, 0x7, 0x20, 0xd2, 0xba, 0x7f, 0x30, 0xd8, 0xa1, 0xa6, 0x1f, 0x9f, 0x9e, 0x5d, 0x2f, 0x8d, 0x57, 0x95, 0x80, 0x6a, 0xab, 0xf9, 0xf6, 0x3e, 0xc3, 0x4e, 0x3d, 0x3b, 0xf7, 0xf1, 0xe9, 0xfa, 0x42, 0xc8, 0xee, 0xcc, 0x60, 0x5b, 0x78, 0x7e, 0xe1, 0x3f, 0x9f, 0xf5, 0xd7, 0x77, 0x7f, 0x3, 0x1c, 0x7f, 0x59, 0xc2, 0x5e, 0xdd, 0xbf, 0x43, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x40, 0xde, 0x8d, 0x6b, 0x0, 0x0, 0x1, 0x4a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x2f, 0x37, 0x46, 0x43, 0x4f, 0x2b, 0x2b, 0x31, 0x2e, 0x2e, 0x34, 0x47, 0x44, 0x50, 0x2a, 0x2a, 0x30, 0x55, 0x52, 0x5f, 0x22, 0x22, 0x27, 0x3d, 0x3a, 0x45, 0x56, 0x52, 0x60, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x43, 0x40, 0x4c, 0x42, 0x40, 0x4b, 0x4c, 0x49, 0x56, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x2d, 0x2d, 0x34, 0x2f, 0x2f, 0x36, 0x2e, 0x2e, 0x35, 0x2c, 0x2c, 0x32, 0x3a, 0x38, 0x41, 0x36, 0x34, 0x3d, 0x44, 0x41, 0x4c, 0x26, 0x26, 0x2b, 0x24, 0x24, 0x28, 0x27, 0x27, 0x2d, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x25, 0x25, 0x2b, 0x23, 0x23, 0x28, 0x44, 0x42, 0x4e, 0x36, 0x34, 0x3e, 0x44, 0x41, 0x4e, 0x26, 0x26, 0x2c, 0x25, 0x25, 0x2a, 0x2a, 0x2a, 0x2f, 0x2b, 0x2b, 0x31, 0x22, 0x22, 0x26, 0x46, 0x42, 0x4f, 0x38, 0x35, 0x3f, 0x2d, 0x2d, 0x33, 0x22, 0x22, 0x27, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x27, 0x27, 0x2b, 0x2e, 0x2e, 0x34, 0x2c, 0x2c, 0x31, 0x29, 0x29, 0x2e, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x24, 0x24, 0x2a, 0x24, 0x24, 0x29, 0x20, 0x20, 0x25, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x28, 0x28, 0x2d, 0x2b, 0x2b, 0x30, 0x29, 0x29, 0x2d, 0x20, 0x20, 0x23, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x22, 0x22, 0x28, 0x27, 0x27, 0x2c, 0x1e, 0x1e, 0x22, 0x50, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x3f, 0x3d, 0x47, 0x4f, 0x4c, 0x59, 0x21, 0x21, 0x26, 0x21, 0x21, 0x25, 0x23, 0x23, 0x27, 0x20, 0x20, 0x24, 0x1d, 0x1d, 0x21, 0x45, 0x42, 0x4d, 0x41, 0x3e, 0x49, 0x40, 0x3e, 0x48, 0x50, 0x4e, 0x5a, 0x1f, 0x1f, 0x24, 0x1f, 0x1f, 0x23, 0x1e, 0x1e, 0x21, 0x52, 0x4e, 0x5c, 0x51, 0x4e, 0x5b, 0x5d, 0x59, 0x69, 0x10, 0x9d, 0xe0, 0x3c, 0x0, 0x0, 0x0, 0x24, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x1d, 0x16, 0xd, 0x7, 0x2, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x43, 0x3a, 0x2d, 0x1b, 0x77, 0xef, 0xe6, 0x49, 0xef, 0xe6, 0xef, 0xe7, 0x77, 0xef, 0xe4, 0x4a, 0xba, 0xea, 0xc1, 0xeb, 0x0, 0x0, 0x0, 0xe6, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6c, 0xcf, 0x3, 0x62, 0x4, 0x51, 0x10, 0x4, 0xd0, 0xaa, 0x31, 0x62, 0xdb, 0xb8, 0x49, 0x2e, 0x9e, 0x3b, 0xc4, 0xb6, 0x9d, 0xc5, 0x58, 0x1f, 0xc1, 0xd6, 0xe8, 0x77, 0xf7, 0x1b, 0x59, 0x6c, 0x2, 0x20, 0x37, 0xaa, 0xc5, 0x17, 0x7e, 0xc7, 0x62, 0x28, 0x45, 0x75, 0xfe, 0x6c, 0xe1, 0x4f, 0x68, 0x86, 0x41, 0x69, 0x44, 0x51, 0x4b, 0xb1, 0xce, 0xcc, 0xe4, 0x83, 0xd7, 0xb0, 0x48, 0x6b, 0x98, 0xe8, 0x9, 0x38, 0x70, 0x8b, 0xa, 0xcc, 0x12, 0x1a, 0xf0, 0x4d, 0xac, 0x87, 0xf3, 0x96, 0x6f, 0x8e, 0x5f, 0x56, 0xc0, 0x53, 0x20, 0x8f, 0xbf, 0xdb, 0x86, 0x58, 0x5b, 0x9, 0xbf, 0x47, 0x80, 0xa, 0x58, 0x1a, 0x38, 0xad, 0x9, 0x5f, 0xac, 0xe3, 0x20, 0xbc, 0x4b, 0x46, 0x4b, 0x0, 0x3a, 0x1a, 0x24, 0xd0, 0x69, 0x85, 0xc0, 0x63, 0x5, 0x60, 0x68, 0xf0, 0x36, 0x7f, 0xf3, 0xaa, 0xbe, 0xe1, 0x61, 0x81, 0x69, 0x5, 0x72, 0x5b, 0x83, 0xe4, 0x6a, 0x59, 0x16, 0xf7, 0x53, 0x47, 0x77, 0x8b, 0xad, 0x12, 0xe4, 0xb9, 0xa3, 0xc1, 0xe6, 0x83, 0x7b, 0x20, 0xd6, 0xb4, 0xe7, 0xbf, 0xed, 0xe1, 0x1a, 0xd8, 0xfa, 0xdf, 0xb9, 0x70, 0xb8, 0x21, 0xd6, 0xbb, 0x17, 0x1b, 0xe3, 0x4c, 0x6a, 0xb0, 0xbd, 0x25, 0x5, 0x3b, 0x5e, 0x7c, 0x21, 0xc0, 0xc2, 0x68, 0xee, 0xf1, 0xbc, 0x6, 0x46, 0xb1, 0xbd, 0x5e, 0x30, 0x5, 0x27, 0x19, 0x24, 0xb8, 0x61, 0x6e, 0xf8, 0xf5, 0xf7, 0xcd, 0x47, 0x16, 0xa0, 0x18, 0x13, 0x6a, 0x64, 0x7d, 0xff, 0x8f, 0x1e, 0x59, 0x84, 0xa2, 0x1b, 0x0, 0xe5, 0xe0, 0x4e, 0x46, 0x1d, 0x98, 0x92, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char panel_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x25, 0x2a, 0x35, 0x32, 0x3b, 0x4a, 0x73, 0x58, 0x4a, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char popup_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xa5, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x35, 0x32, 0x3b, 0xf, 0xeb, 0x7f, 0x60, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x36, 0x47, 0xbf, 0x88, 0xd1, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xaf, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0xc9, 0x12, 0x82, 0x30, 0x10, 0x4, 0xd0, 0x1, 0x12, 0xb6, 0x0, 0x21, 0x2c, 0xb2, 0xaa, 0xa0, 0xa8, 0x80, 0x88, 0x8, 0xf8, 0xff, 0xbf, 0x66, 0x98, 0x93, 0xa5, 0xef, 0xd8, 0x55, 0xd3, 0xd5, 0x3, 0xa0, 0xa8, 0x1a, 0xa1, 0xba, 0x44, 0x89, 0xa6, 0x2a, 0x0, 0x8a, 0x41, 0x4d, 0xcb, 0x66, 0x8e, 0xc3, 0x6c, 0xcb, 0xa4, 0x86, 0x2, 0x2a, 0x75, 0x3d, 0xee, 0x8b, 0x20, 0x10, 0x3e, 0xf7, 0x5c, 0xaa, 0x82, 0x66, 0x7a, 0x61, 0x14, 0xef, 0xa4, 0x38, 0xa, 0x3d, 0x53, 0x3, 0x62, 0xf1, 0xa4, 0xed, 0x50, 0x9b, 0x70, 0x8b, 0x0, 0xb5, 0xd3, 0xac, 0xeb, 0x51, 0x97, 0xa5, 0x36, 0x5, 0x9d, 0x89, 0xbc, 0xbf, 0xa3, 0x3e, 0x17, 0x4c, 0x7, 0xdd, 0x9, 0x8a, 0xe1, 0x81, 0x86, 0x22, 0x70, 0x30, 0x28, 0xc7, 0x27, 0x1a, 0x4b, 0xc, 0x98, 0xd8, 0x4f, 0x2f, 0x34, 0xed, 0xb7, 0x13, 0x59, 0x7a, 0x98, 0x17, 0x34, 0x1f, 0xb7, 0x52, 0x52, 0xf1, 0x7a, 0x5d, 0xde, 0xd2, 0xb2, 0x9e, 0x78, 0x45, 0xb6, 0x61, 0xe7, 0xba, 0xb9, 0x48, 0xcd, 0xf5, 0xb6, 0xd, 0xc3, 0xe9, 0xe9, 0xd7, 0xf4, 0xbf, 0xe7, 0x7e, 0xdf, 0xff, 0x0, 0xda, 0x19, 0x15, 0x34, 0xd5, 0xa4, 0x90, 0x50, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xa2, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3b, 0x3b, 0x43, 0x42, 0x42, 0x4b, 0x3e, 0x3e, 0x47, 0x3e, 0x3e, 0x46, 0x41, 0x41, 0x4a, 0x0, 0x0, 0x0, 0x3d, 0x3d, 0x45, 0x3b, 0x3b, 0x43, 0x3a, 0x3a, 0x42, 0x38, 0x38, 0x41, 0x37, 0x37, 0x3e, 0x36, 0x36, 0x3d, 0x35, 0x35, 0x3c, 0x0, 0x0, 0x0, 0x38, 0x38, 0x40, 0x38, 0x38, 0x40, 0x31, 0x31, 0x38, 0x34, 0x34, 0x3b, 0x34, 0x34, 0x3b, 0x39, 0x39, 0x3f, 0x31, 0x31, 0x38, 0x2f, 0x2f, 0x36, 0x2d, 0x2d, 0x33, 0x2c, 0x2c, 0x32, 0x2b, 0x2b, 0x31, 0x2a, 0x2a, 0x31, 0x2a, 0x2a, 0x30, 0x29, 0x29, 0x30, 0x29, 0x29, 0x2f, 0x28, 0x28, 0x2e, 0x28, 0x28, 0x2d, 0x27, 0x27, 0x2d, 0x27, 0x27, 0x2c, 0x29, 0x29, 0x2e, 0x26, 0x26, 0x2c, 0x36, 0xc6, 0xc8, 0x93, 0x0, 0x0, 0x0, 0x28, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0x4, 0x13, 0x19, 0x1f, 0x22, 0x23, 0x16, 0x27, 0x35, 0x3f, 0x45, 0x46, 0x94, 0xf5, 0xfa, 0xfb, 0xf5, 0x40, 0xfc, 0xfb, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0x1a, 0xf5, 0xf6, 0x95, 0xfa, 0xfb, 0xf4, 0x94, 0x71, 0xda, 0xac, 0x92, 0x0, 0x0, 0x0, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0x8f, 0x35, 0x82, 0xc3, 0x0, 0xc, 0x4, 0x77, 0x24, 0x85, 0xba, 0xe3, 0xff, 0xff, 0xee, 0xca, 0x74, 0x41, 0xdb, 0x32, 0xf3, 0x94, 0x82, 0x85, 0x10, 0x1d, 0x92, 0xb2, 0x3, 0x8e, 0x95, 0x77, 0x93, 0x6c, 0x28, 0xed, 0x15, 0x54, 0x67, 0xa6, 0x41, 0x3e, 0x8, 0x9c, 0xc3, 0xf4, 0xf2, 0xf6, 0x2a, 0x80, 0xf8, 0x44, 0x2d, 0x79, 0x2d, 0x20, 0xe0, 0x2, 0xa8, 0xc3, 0x2e, 0x6f, 0xc, 0x9e, 0x4c, 0x3c, 0x21, 0x4, 0xd8, 0xf0, 0x2, 0x28, 0x24, 0xcd, 0x3, 0xa9, 0x19, 0x64, 0xce, 0x83, 0x4c, 0x45, 0xe6, 0x69, 0x1a, 0xd8, 0xe9, 0x99, 0x96, 0x7f, 0x77, 0x37, 0x59, 0x83, 0xcc, 0xef, 0x7f, 0x89, 0x1f, 0x8e, 0xbf, 0x95, 0xd3, 0x1d, 0xf0, 0xff, 0x7a, 0x63, 0x7e, 0x86, 0xcb, 0x73, 0x8c, 0x5e, 0xee, 0xca, 0xb1, 0xad, 0x5f, 0x3, 0xaf, 0xdb, 0x49, 0x94, 0x4b, 0x90, 0x40, 0xdf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char popup_bg_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x7b, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x67, 0x7a, 0x85, 0x66, 0x7a, 0x86, 0x68, 0x7b, 0x86, 0x57, 0x51, 0x51, 0x4c, 0x42, 0x40, 0x4d, 0x43, 0x41, 0x56, 0x4c, 0x4b, 0x4d, 0x44, 0x41, 0x4e, 0x44, 0x42, 0x4f, 0x45, 0x43, 0x67, 0x7b, 0x87, 0x4f, 0x44, 0x43, 0x50, 0x45, 0x44, 0x52, 0x46, 0x44, 0x51, 0x46, 0x45, 0x4b, 0x40, 0x3f, 0x51, 0x47, 0x45, 0x52, 0x48, 0x46, 0x53, 0x48, 0x47, 0x4b, 0x41, 0x3f, 0x54, 0x49, 0x46, 0x55, 0x4a, 0x47, 0x55, 0x49, 0x47, 0x68, 0x7c, 0x88, 0x4a, 0x40, 0x3e, 0x55, 0x4b, 0x49, 0x56, 0x4d, 0x4b, 0x53, 0x49, 0x47, 0x50, 0x46, 0x44, 0x4a, 0x41, 0x3e, 0x48, 0x3e, 0x3c, 0x4b, 0x42, 0x3f, 0x49, 0x3f, 0x3d, 0x46, 0x3d, 0x3c, 0x47, 0x3d, 0x3b, 0x47, 0x3e, 0x3b, 0x49, 0x40, 0x3d, 0x45, 0x3c, 0x3b, 0x46, 0x3c, 0x3a, 0xff, 0xff, 0xff, 0x2e, 0x48, 0xbd, 0x3e, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x28, 0xbd, 0xb0, 0xb5, 0xb2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb3, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x2d, 0x8f, 0xdb, 0x16, 0x82, 0x20, 0x10, 0x45, 0x11, 0x19, 0x12, 0x91, 0x54, 0x44, 0x93, 0xb2, 0x48, 0xa1, 0xfc, 0xff, 0x3f, 0xec, 0xa0, 0xed, 0xb7, 0xd9, 0x73, 0xd6, 0x5c, 0x18, 0x3, 0x5, 0x2f, 0x1, 0x2f, 0xd8, 0x49, 0xc1, 0x5, 0x49, 0x40, 0xe2, 0x54, 0xc5, 0x85, 0x2a, 0xa9, 0x80, 0xac, 0x48, 0x64, 0xc3, 0x89, 0x64, 0x7d, 0x20, 0x89, 0x34, 0x2, 0x82, 0x48, 0x35, 0xe6, 0x7a, 0x6d, 0x1b, 0x45, 0x39, 0xc2, 0x3b, 0x92, 0x4d, 0x6f, 0x87, 0xc1, 0xf6, 0x30, 0x4e, 0x33, 0xed, 0xb2, 0x18, 0xa7, 0xdb, 0x64, 0x8d, 0x24, 0x37, 0x33, 0xed, 0x9d, 0xac, 0xfb, 0xf1, 0xfe, 0x18, 0x97, 0xa7, 0x3a, 0xc4, 0xcb, 0x51, 0x16, 0xf7, 0xc9, 0x42, 0x78, 0x88, 0xf0, 0x76, 0xca, 0xb4, 0xcb, 0x62, 0xd, 0x2, 0x2b, 0xc4, 0x16, 0x7c, 0x5e, 0x63, 0x9e, 0x35, 0x75, 0x6b, 0xd4, 0x58, 0x9b, 0x3e, 0x98, 0x8b, 0xbb, 0xd0, 0x8f, 0xa2, 0x64, 0x88, 0xc4, 0xb0, 0x7a, 0xe7, 0x3a, 0x1f, 0x12, 0x2, 0xf9, 0xb2, 0x6f, 0x8c, 0x31, 0x84, 0x18, 0xd3, 0x26, 0xf8, 0xf1, 0x8c, 0x16, 0xfb, 0x9e, 0xd2, 0xbe, 0xb, 0x5d, 0xfe, 0xff, 0xe5, 0x7a, 0x6, 0x67, 0xf9, 0x3, 0x92, 0x36, 0xd, 0x2d, 0xc1, 0xf2, 0x6d, 0x3c, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x78, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x67, 0x7a, 0x85, 0x66, 0x7a, 0x86, 0x68, 0x7b, 0x86, 0x57, 0x51, 0x51, 0x4c, 0x42, 0x40, 0x4d, 0x43, 0x41, 0x56, 0x4c, 0x4b, 0x4d, 0x44, 0x41, 0x4e, 0x44, 0x42, 0x4f, 0x45, 0x43, 0x67, 0x7b, 0x87, 0x4f, 0x44, 0x43, 0x50, 0x45, 0x44, 0x52, 0x46, 0x44, 0x51, 0x46, 0x45, 0x4b, 0x40, 0x3f, 0x51, 0x47, 0x45, 0x52, 0x48, 0x46, 0x53, 0x48, 0x47, 0x4b, 0x41, 0x3f, 0x54, 0x49, 0x46, 0x55, 0x4a, 0x47, 0x55, 0x49, 0x47, 0x68, 0x7c, 0x88, 0x4a, 0x40, 0x3e, 0x55, 0x4b, 0x49, 0x56, 0x4d, 0x4b, 0x53, 0x49, 0x47, 0x50, 0x46, 0x44, 0x4a, 0x41, 0x3e, 0x48, 0x3e, 0x3c, 0x4b, 0x42, 0x3f, 0x49, 0x3f, 0x3d, 0x46, 0x3d, 0x3c, 0x47, 0x3d, 0x3b, 0x47, 0x3e, 0x3b, 0x49, 0x40, 0x3d, 0x45, 0x3c, 0x3b, 0x46, 0x3c, 0x3a, 0xdd, 0x63, 0x56, 0x8d, 0x0, 0x0, 0x0, 0xad, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2d, 0x88, 0x35, 0x42, 0x4, 0x0, 0xc, 0x4, 0x77, 0x93, 0x9c, 0xbb, 0xf4, 0xc8, 0xff, 0xdf, 0x84, 0xb5, 0xb8, 0x5b, 0x84, 0x0, 0x37, 0xc5, 0xca, 0x10, 0xd, 0xc9, 0xce, 0xaa, 0xea, 0x24, 0x40, 0xca, 0x41, 0x64, 0x2b, 0x5, 0x87, 0x34, 0xa8, 0x88, 0x54, 0xef, 0x82, 0x80, 0x89, 0x34, 0x36, 0x96, 0xe0, 0x14, 0xa4, 0x12, 0xa6, 0x24, 0x18, 0xe1, 0xa8, 0x50, 0x59, 0x7c, 0x73, 0x30, 0x50, 0x55, 0x4a, 0x31, 0xd7, 0xb4, 0x89, 0xa1, 0x51, 0xb2, 0x9c, 0x1, 0x2c, 0x4, 0x83, 0x15, 0x12, 0x30, 0xab, 0xe9, 0x5a, 0x1, 0xb4, 0x40, 0xa1, 0x29, 0xbe, 0x75, 0xe, 0x5a, 0x70, 0xbe, 0x2a, 0xff, 0x12, 0xf1, 0xef, 0x1b, 0x5f, 0x8d, 0x5b, 0x68, 0xd, 0xdc, 0xe3, 0xf1, 0x71, 0x16, 0x3e, 0x5b, 0xc8, 0x33, 0xa9, 0xc7, 0xbc, 0x7f, 0xa4, 0x22, 0x6a, 0xb5, 0x90, 0xcb, 0xb2, 0x1a, 0x25, 0x67, 0x8b, 0x8f, 0x6f, 0xf8, 0x64, 0xa8, 0x35, 0x7a, 0x25, 0xa8, 0xa7, 0x1, 0x38, 0xc, 0xcc, 0xab, 0x4c, 0x5, 0xea, 0xe3, 0x76, 0x2f, 0x54, 0x93, 0xf3, 0xf, 0x4f, 0x10, 0x8d, 0x4c, 0x16, 0x9d, 0xcf, 0x1f, 0xd1, 0xf9, 0x3, 0x34, 0xc8, 0x4a, 0xb4, 0x1d, 0xb, 0xcd, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char popup_checked_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xa3, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x85, 0xcd, 0xa1, 0xa, 0xc2, 0x50, 0x0, 0x85, 0xe1, 0xff, 0xdc, 0x5d, 0xd8, 0x14, 0x4, 0xab, 0x69, 0x37, 0xac, 0x98, 0xd5, 0x27, 0xb0, 0x89, 0x16, 0x8b, 0xd5, 0xf7, 0xd0, 0xec, 0x73, 0xf8, 0x4, 0x16, 0x61, 0x4d, 0x10, 0xc, 0x16, 0xa3, 0x61, 0x71, 0xab, 0x16, 0xeb, 0x84, 0x3b, 0xae, 0x45, 0x8b, 0xa, 0x9e, 0x78, 0xce, 0x7, 0x7, 0xfe, 0x44, 0xbf, 0xca, 0xa2, 0x28, 0x3a, 0x71, 0x1c, 0x1f, 0x24, 0x3d, 0xcc, 0xe7, 0x18, 0x42, 0x50, 0x92, 0x24, 0x5b, 0x49, 0x23, 0xa0, 0xfd, 0x5, 0xaa, 0xaa, 0x5a, 0x1, 0x73, 0xe0, 0x1e, 0x45, 0xd1, 0x42, 0x65, 0x59, 0x9e, 0x80, 0x96, 0xf7, 0x7e, 0x62, 0xad, 0x1d, 0x2, 0xfb, 0x97, 0x9d, 0x39, 0xe7, 0x72, 0x1b, 0x42, 0x88, 0x25, 0xd, 0xac, 0xb5, 0x47, 0xa0, 0x7, 0x18, 0x60, 0xed, 0x9c, 0xcb, 0x1, 0x4c, 0xd3, 0x34, 0x53, 0xe0, 0xa, 0xf4, 0x81, 0x2e, 0xb0, 0x4b, 0xd3, 0x74, 0xf3, 0xbe, 0x34, 0x59, 0x96, 0xdd, 0xbc, 0xf7, 0x63, 0xe0, 0x2, 0x9c, 0xeb, 0xba, 0x5e, 0x4a, 0xa, 0x6f, 0xf0, 0x4, 0x57, 0x3d, 0x2c, 0x27, 0x2b, 0xe9, 0x62, 0x6b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x56, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x3, 0x6e, 0xf0, 0xde, 0x3f, 0xf5, 0xe0, 0x30, 0x9c, 0xfb, 0x9f, 0xf1, 0xc1, 0xda, 0x7, 0xff, 0x1f, 0x9c, 0x85, 0xb, 0x3c, 0xa8, 0x1, 0x72, 0xdf, 0x3d, 0x56, 0x61, 0x78, 0x70, 0xf8, 0xc1, 0x99, 0x3b, 0x62, 0xf, 0xbc, 0x1e, 0xfc, 0x5, 0x42, 0x2f, 0xa0, 0xcc, 0xfd, 0x53, 0x40, 0x99, 0x6b, 0xf, 0xde, 0x3, 0xc9, 0x6a, 0xb0, 0x52, 0xa0, 0xec, 0xe5, 0x7, 0xff, 0x81, 0x70, 0xed, 0x7f, 0x46, 0x20, 0x17, 0x2a, 0x74, 0xfa, 0xc1, 0xb1, 0x1b, 0xbc, 0x10, 0x1e, 0x0, 0xfd, 0x1f, 0x33, 0x9, 0xf7, 0x50, 0x16, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char popup_hover_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x20, 0x2e, 0x31, 0x83, 0xae, 0xb7, 0xb3, 0xd8, 0xe1, 0xaf, 0xd5, 0xde, 0xac, 0xd2, 0xdb, 0xa9, 0xcf, 0xd8, 0xa5, 0xcc, 0xd5, 0xa2, 0xc9, 0xd2, 0x9e, 0xc6, 0xcf, 0x9b, 0xc3, 0xcc, 0x97, 0xc0, 0xc9, 0x94, 0xbd, 0xc6, 0x91, 0xba, 0xc3, 0x8d, 0xb7, 0xc0, 0xff, 0xff, 0xff, 0x73, 0xd4, 0x4e, 0xcb, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x14, 0x4, 0x3, 0x1, 0x6, 0x21, 0x25, 0x30, 0x50, 0x64, 0x10, 0x32, 0x6, 0x3, 0x20, 0xc3, 0x5, 0xc, 0x80, 0x8c, 0x50, 0x30, 0x0, 0x32, 0xd2, 0xc0, 0x0, 0xc8, 0x28, 0x7, 0x3, 0x20, 0xa3, 0x3, 0xc, 0x80, 0x8c, 0x99, 0x60, 0x0, 0x64, 0xac, 0x2, 0x3, 0x20, 0x63, 0x37, 0x18, 0x0, 0x19, 0x67, 0xc0, 0x0, 0xc8, 0xb8, 0xb, 0x6, 0x40, 0xc6, 0x3b, 0x30, 0x50, 0x44, 0x58, 0xa, 0x73, 0x6, 0x0, 0xe9, 0xb4, 0x2d, 0xf5, 0x51, 0xd4, 0xb8, 0xa1, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0x20, 0x2e, 0x31, 0x83, 0xae, 0xb7, 0xb3, 0xd8, 0xe1, 0xaf, 0xd5, 0xde, 0xac, 0xd2, 0xdb, 0xa9, 0xcf, 0xd8, 0xa5, 0xcc, 0xd5, 0xa2, 0xc9, 0xd2, 0x9e, 0xc6, 0xcf, 0x9b, 0xc3, 0xcc, 0x97, 0xc0, 0xc9, 0x94, 0xbd, 0xc6, 0x91, 0xba, 0xc3, 0x8d, 0xb7, 0xc0, 0x9c, 0x2c, 0x91, 0xa9, 0x0, 0x0, 0x0, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x62, 0x14, 0x4, 0x3, 0x1, 0x26, 0x41, 0x28, 0x60, 0x62, 0x80, 0xd0, 0xc, 0x74, 0x61, 0x98, 0x80, 0x1, 0x3, 0xd3, 0x7b, 0x28, 0x0, 0x0, 0x1a, 0x86, 0xe, 0x98, 0x2c, 0x61, 0xda, 0x2e, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char popup_unchecked_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x18, 0x32, 0xe0, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0x9f, 0x18, 0x32, 0xe0, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char popup_window_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x46, 0x8, 0x3, 0x0, 0x0, 0x0, 0x8d, 0x2b, 0xf6, 0x48, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x6e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xe8, 0xe5, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x22, 0x0, 0x0, 0x0, 0x1a, 0x19, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x21, 0x17, 0x16, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1b, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1e, 0x1c, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x0, 0x0, 0x0, 0x20, 0x20, 0x25, 0x20, 0x1d, 0x25, 0x20, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x20, 0x1d, 0x1a, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30, 0x38, 0xe8, 0xe5, 0xf1, 0xe5, 0xe2, 0xeb, 0xe3, 0xe1, 0xe8, 0xe1, 0xdf, 0xe7, 0xe0, 0xde, 0xe6, 0xdf, 0xdd, 0xe5, 0xde, 0xdc, 0xe4, 0xdd, 0xdb, 0xe3, 0xdc, 0xda, 0xe2, 0xda, 0xd8, 0xe0, 0xd9, 0xd7, 0xdf, 0xd7, 0xd6, 0xdf, 0xd6, 0xd4, 0xdd, 0xd5, 0xd3, 0xdc, 0xd4, 0xd1, 0xdb, 0xd3, 0xd0, 0xda, 0xd1, 0xce, 0xd8, 0xd0, 0xcd, 0xd7, 0xcf, 0xcd, 0xd7, 0xe2, 0xdf, 0xeb, 0x48, 0x46, 0x51, 0x42, 0x40, 0x4b, 0x40, 0x3e, 0x48, 0x40, 0x3d, 0x48, 0x48, 0x45, 0x50, 0x42, 0x3f, 0x4a, 0x3f, 0x3d, 0x48, 0x47, 0x44, 0x50, 0x41, 0x3f, 0x4a, 0x3f, 0x3d, 0x47, 0x41, 0x3e, 0x49, 0x3f, 0x3c, 0x47, 0x46, 0x43, 0x4f, 0x3e, 0x3c, 0x46, 0x40, 0x3e, 0x49, 0x3d, 0x3b, 0x46, 0x45, 0x43, 0x4e, 0x3d, 0x3b, 0x45, 0x44, 0x42, 0x4d, 0x3d, 0x3a, 0x45, 0x3e, 0x3c, 0x47, 0x3c, 0x3a, 0x44, 0x43, 0x42, 0x4c, 0x43, 0x40, 0x4c, 0x3e, 0x3b, 0x46, 0x3b, 0x39, 0x43, 0x43, 0x3f, 0x4c, 0x43, 0x3f, 0x4b, 0x3a, 0x38, 0x42, 0x42, 0x3e, 0x4b, 0x42, 0x3e, 0x49, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3f, 0x3e, 0x48, 0x39, 0x37, 0x40, 0x38, 0x36, 0x40, 0x3e, 0x3d, 0x48, 0x38, 0x36, 0x3f, 0x3e, 0x3d, 0x47, 0x3a, 0x38, 0x41, 0x38, 0x35, 0x3f, 0x37, 0x35, 0x3e, 0x39, 0x36, 0x40, 0x37, 0x34, 0x3e, 0x3d, 0x3a, 0x46, 0x36, 0x34, 0x3d, 0x3d, 0x3a, 0x44, 0x37, 0x35, 0x3f, 0x35, 0x33, 0x3c, 0x46, 0x44, 0x4f, 0xff, 0xff, 0xff, 0x7e, 0xde, 0x1d, 0x81, 0x0, 0x0, 0x0, 0x33, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xa2, 0x3, 0x9, 0x17, 0xc, 0x20, 0xf, 0x2a, 0x5e, 0x12, 0x30, 0x68, 0x46, 0x20, 0x4e, 0xa2, 0x7d, 0x3a, 0x4f, 0xa4, 0x7d, 0x3f, 0x25, 0x60, 0xc0, 0xb8, 0x57, 0x1d, 0xba, 0x59, 0xbd, 0x5b, 0x22, 0xbf, 0x5e, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xa1, 0x9f, 0x9e, 0x52, 0x92, 0x15, 0x44, 0x7e, 0xd8, 0x5, 0xc7, 0xf4, 0xac, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x79, 0xa1, 0xdc, 0xd4, 0xd0, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x1, 0xe8, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0xd6, 0xd9, 0x53, 0xd3, 0x60, 0x14, 0xc6, 0xe1, 0x92, 0x5a, 0xa3, 0x44, 0xa3, 0xd6, 0x85, 0xa0, 0xb1, 0x5a, 0xcb, 0xda, 0xbd, 0x7c, 0xb8, 0xef, 0x2b, 0x69, 0x21, 0xd0, 0xda, 0x22, 0x25, 0xd, 0x69, 0x20, 0x60, 0x69, 0x11, 0x2a, 0x22, 0xcb, 0x9f, 0xef, 0x78, 0x97, 0x7e, 0xe7, 0x3d, 0x33, 0x1d, 0xbd, 0x70, 0xfc, 0x5d, 0x3f, 0x77, 0xe7, 0xe2, 0x3d, 0x91, 0xc8, 0x7f, 0xd8, 0x88, 0x60, 0x1a, 0x21, 0x54, 0xcc, 0x3f, 0x84, 0xcd, 0xb, 0x4a, 0x1f, 0x31, 0xfd, 0x1d, 0x7d, 0xcc, 0x4, 0xe8, 0x13, 0x26, 0x40, 0x9f, 0x32, 0x1, 0xfa, 0x8c, 0x9, 0xd0, 0xe7, 0x4c, 0x80, 0xbe, 0x60, 0x2, 0xf4, 0x25, 0x13, 0xa0, 0xaf, 0x98, 0x0, 0x7d, 0xcd, 0x44, 0xa8, 0x22, 0xde, 0x30, 0x49, 0x54, 0x89, 0x9e, 0x13, 0x6f, 0x99, 0x64, 0x1a, 0x3b, 0x2f, 0xde, 0x31, 0x49, 0x54, 0xbd, 0x70, 0x51, 0xbc, 0x67, 0x92, 0xe8, 0xa8, 0x76, 0x49, 0x7c, 0x60, 0x12, 0x97, 0xf5, 0x68, 0x88, 0xea, 0x57, 0xae, 0x8a, 0x8f, 0x4c, 0xe2, 0x5a, 0x7c, 0x34, 0x4c, 0xaf, 0xdf, 0x10, 0x9f, 0x98, 0xc4, 0xcd, 0x5b, 0x21, 0xaa, 0x8c, 0x19, 0xe3, 0xb, 0x56, 0x19, 0x66, 0x2d, 0xdc, 0xbe, 0x63, 0x2a, 0x43, 0xd2, 0xbb, 0x9, 0x7d, 0x58, 0x7a, 0xef, 0x7e, 0x72, 0x58, 0xfa, 0x20, 0x35, 0x36, 0x2c, 0x1d, 0x37, 0x8, 0xad, 0xc0, 0x0, 0x5d, 0x5c, 0xb2, 0x61, 0x4b, 0x8b, 0x32, 0x9d, 0x58, 0x5e, 0xa9, 0xc2, 0x56, 0x96, 0x27, 0x8, 0xad, 0x7d, 0x86, 0xd5, 0x28, 0xad, 0xd7, 0x1a, 0xb0, 0x5a, 0x9d, 0xd2, 0x55, 0x4c, 0x57, 0x1, 0xad, 0x7c, 0x81, 0x55, 0x8, 0x9d, 0x5c, 0xb3, 0x9b, 0x30, 0x7b, 0x6d, 0x52, 0xa2, 0x53, 0xeb, 0x55, 0x7, 0x56, 0x5d, 0x9f, 0x22, 0xb4, 0xe5, 0xc2, 0x5a, 0x94, 0x6e, 0x34, 0x30, 0x6d, 0x6c, 0x10, 0xea, 0xb5, 0x7d, 0x58, 0xdb, 0x93, 0xe9, 0xf4, 0x66, 0x13, 0xd3, 0xe6, 0xe6, 0xb4, 0x4c, 0xb7, 0x9c, 0x0, 0xe6, 0x6c, 0x11, 0xba, 0xed, 0x62, 0xea, 0x6e, 0x13, 0xba, 0xe3, 0x7e, 0x85, 0xb9, 0x3b, 0x84, 0x96, 0xfd, 0xe, 0xcc, 0x2f, 0x13, 0xba, 0xeb, 0x77, 0x61, 0xfe, 0x2e, 0xa1, 0x76, 0xd0, 0x83, 0x5, 0x36, 0xa1, 0x7b, 0xc1, 0x37, 0x58, 0xb0, 0x27, 0xd3, 0x99, 0xfd, 0x83, 0x3e, 0xec, 0x60, 0x7f, 0x46, 0xa2, 0xb3, 0xad, 0xce, 0x77, 0x58, 0xa7, 0x35, 0x2b, 0xd3, 0xf6, 0x21, 0xa6, 0x87, 0x6d, 0x40, 0x7f, 0xc0, 0x0, 0x3d, 0xea, 0xfd, 0x84, 0xf5, 0x8e, 0x8, 0x75, 0xfa, 0x98, 0xf6, 0x1d, 0x42, 0x8f, 0x39, 0x7a, 0x4c, 0xe9, 0xc9, 0x29, 0xec, 0x64, 0x90, 0x46, 0x92, 0xa9, 0xb4, 0x75, 0xca, 0x64, 0xa5, 0x53, 0xc9, 0xc8, 0x1f, 0xd2, 0xc, 0x4f, 0x33, 0x3, 0x54, 0x4f, 0x64, 0x79, 0x9a, 0x4d, 0xe8, 0x21, 0x6a, 0xe6, 0xf2, 0x1e, 0x47, 0xbd, 0x7c, 0xce, 0xc, 0xd1, 0x42, 0xb1, 0x54, 0xef, 0x62, 0xd9, 0x3d, 0x2b, 0x15, 0xb, 0x21, 0xaa, 0x6a, 0xc6, 0xdc, 0x99, 0x67, 0x81, 0xbc, 0xfa, 0x9c, 0xa1, 0xa9, 0x21, 0x1a, 0x35, 0xe3, 0x46, 0x29, 0x9f, 0xcd, 0xa4, 0xa5, 0x32, 0xd9, 0x7c, 0xc9, 0x88, 0x9b, 0xe1, 0xe1, 0x54, 0x62, 0xa6, 0x56, 0xcc, 0x25, 0x52, 0xa4, 0x44, 0xae, 0xa8, 0x99, 0xb1, 0xd0, 0x5, 0x7e, 0x3f, 0x4, 0x6a, 0xc1, 0xd4, 0x93, 0x24, 0xdd, 0x2c, 0xa8, 0xd1, 0x1, 0xf9, 0xf, 0xfb, 0x5, 0x66, 0x6f, 0x2a, 0x9a, 0xa8, 0x51, 0x81, 0xce, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x0, 0x0, 0x0, 0x46, 0x8, 0x3, 0x0, 0x0, 0x0, 0x8d, 0x2b, 0xf6, 0x48, 0x0, 0x0, 0x1, 0x6b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xe8, 0xe5, 0xf1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x22, 0x0, 0x0, 0x0, 0x1a, 0x19, 0x1c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x1d, 0x21, 0x17, 0x16, 0x19, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1b, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x1e, 0x1c, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x20, 0x1e, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x21, 0x1f, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x22, 0x20, 0x25, 0x0, 0x0, 0x0, 0x20, 0x20, 0x25, 0x20, 0x1d, 0x25, 0x20, 0x1d, 0x22, 0x1d, 0x1d, 0x22, 0x1d, 0x1d, 0x20, 0x1d, 0x1a, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32, 0x30, 0x38, 0xe8, 0xe5, 0xf1, 0xe5, 0xe2, 0xeb, 0xe3, 0xe1, 0xe8, 0xe1, 0xdf, 0xe7, 0xe0, 0xde, 0xe6, 0xdf, 0xdd, 0xe5, 0xde, 0xdc, 0xe4, 0xdd, 0xdb, 0xe3, 0xdc, 0xda, 0xe2, 0xda, 0xd8, 0xe0, 0xd9, 0xd7, 0xdf, 0xd7, 0xd6, 0xdf, 0xd6, 0xd4, 0xdd, 0xd5, 0xd3, 0xdc, 0xd4, 0xd1, 0xdb, 0xd3, 0xd0, 0xda, 0xd1, 0xce, 0xd8, 0xd0, 0xcd, 0xd7, 0xcf, 0xcd, 0xd7, 0xe2, 0xdf, 0xeb, 0x48, 0x46, 0x51, 0x42, 0x40, 0x4b, 0x40, 0x3e, 0x48, 0x40, 0x3d, 0x48, 0x48, 0x45, 0x50, 0x42, 0x3f, 0x4a, 0x3f, 0x3d, 0x48, 0x47, 0x44, 0x50, 0x41, 0x3f, 0x4a, 0x3f, 0x3d, 0x47, 0x41, 0x3e, 0x49, 0x3f, 0x3c, 0x47, 0x46, 0x43, 0x4f, 0x3e, 0x3c, 0x46, 0x40, 0x3e, 0x49, 0x3d, 0x3b, 0x46, 0x45, 0x43, 0x4e, 0x3d, 0x3b, 0x45, 0x44, 0x42, 0x4d, 0x3d, 0x3a, 0x45, 0x3e, 0x3c, 0x47, 0x3c, 0x3a, 0x44, 0x43, 0x42, 0x4c, 0x43, 0x40, 0x4c, 0x3e, 0x3b, 0x46, 0x3b, 0x39, 0x43, 0x43, 0x3f, 0x4c, 0x43, 0x3f, 0x4b, 0x3a, 0x38, 0x42, 0x42, 0x3e, 0x4b, 0x42, 0x3e, 0x49, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3f, 0x3e, 0x48, 0x39, 0x37, 0x40, 0x38, 0x36, 0x40, 0x3e, 0x3d, 0x48, 0x38, 0x36, 0x3f, 0x3e, 0x3d, 0x47, 0x3a, 0x38, 0x41, 0x38, 0x35, 0x3f, 0x37, 0x35, 0x3e, 0x39, 0x36, 0x40, 0x37, 0x34, 0x3e, 0x3d, 0x3a, 0x46, 0x36, 0x34, 0x3d, 0x3d, 0x3a, 0x44, 0x37, 0x35, 0x3f, 0x35, 0x33, 0x3c, 0x46, 0x44, 0x4f, 0xac, 0xa5, 0x1, 0x25, 0x0, 0x0, 0x0, 0x33, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xa2, 0x3, 0x9, 0x17, 0xc, 0x20, 0xf, 0x2a, 0x5e, 0x12, 0x30, 0x68, 0x46, 0x20, 0x4e, 0xa2, 0x7d, 0x3a, 0x4f, 0xa4, 0x7d, 0x3f, 0x25, 0x60, 0xc0, 0xb8, 0x57, 0x1d, 0xba, 0x59, 0xbd, 0x5b, 0x22, 0xbf, 0x5e, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xa1, 0x9f, 0x9e, 0x52, 0x92, 0x15, 0x44, 0x7e, 0xd8, 0x5, 0xc7, 0xf4, 0xac, 0x0, 0x0, 0x1, 0x98, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0xd6, 0x55, 0x9e, 0x14, 0x31, 0x10, 0x80, 0xf1, 0xb2, 0x20, 0x1d, 0xdc, 0x9d, 0x3b, 0x2c, 0xa7, 0x87, 0x4b, 0xe0, 0xee, 0xd0, 0x82, 0xcb, 0xea, 0xb4, 0x86, 0x79, 0x23, 0x93, 0xaa, 0xcc, 0xf, 0xd7, 0xfd, 0x9e, 0xff, 0xed, 0x1d, 0x21, 0xf8, 0xe2, 0xfe, 0x1c, 0x8a, 0x17, 0x32, 0xa1, 0xa2, 0x2b, 0x48, 0x66, 0xb8, 0xa2, 0x28, 0x10, 0x9a, 0xd1, 0xf7, 0x3d, 0x16, 0x66, 0xfa, 0x45, 0x74, 0x9b, 0xd2, 0x97, 0x52, 0xe2, 0x2f, 0xa6, 0x40, 0x5f, 0x4c, 0x1d, 0xf3, 0x97, 0x52, 0x5e, 0x46, 0xf7, 0xee, 0xe3, 0x88, 0x8a, 0x48, 0x9e, 0x8a, 0xec, 0x8c, 0x28, 0x2c, 0xa7, 0xf0, 0x99, 0xd2, 0x6e, 0xe7, 0x8e, 0x10, 0x9b, 0xd1, 0x11, 0xe7, 0xe, 0xd1, 0x17, 0x8e, 0x2, 0xe6, 0x55, 0xf8, 0x42, 0x4a, 0x74, 0x18, 0xbe, 0xf8, 0xac, 0x9b, 0x5f, 0x4a, 0xb7, 0x36, 0x20, 0xa5, 0xf9, 0x2f, 0x90, 0x50, 0x11, 0x36, 0x13, 0x49, 0xa9, 0xe7, 0x6c, 0x5e, 0xcf, 0x2e, 0x99, 0xf4, 0xd, 0xb8, 0x8c, 0x5, 0xa7, 0x28, 0x8, 0x98, 0x9, 0x68, 0xba, 0x41, 0x66, 0x1b, 0x8a, 0xa2, 0xb0, 0x4d, 0x59, 0x30, 0xa5, 0x94, 0xa3, 0x94, 0x52, 0x0, 0x6f, 0x53, 0x6f, 0x7c, 0x82, 0x16, 0xcc, 0x5a, 0x51, 0x14, 0xbd, 0x98, 0x79, 0x4c, 0x29, 0x72, 0xee, 0xac, 0x8c, 0xea, 0xac, 0xb9, 0x51, 0xa0, 0xce, 0xa, 0x44, 0x60, 0x46, 0xa4, 0x28, 0x2, 0x9b, 0x1, 0x2a, 0x5a, 0xa, 0x9a, 0x49, 0xa9, 0xe8, 0x79, 0x20, 0x33, 0x38, 0xaf, 0x68, 0xc5, 0x68, 0xc6, 0x95, 0xa2, 0xe7, 0x72, 0x67, 0x3d, 0x97, 0x52, 0x24, 0xcf, 0x66, 0x9e, 0x30, 0xa5, 0xef, 0x5a, 0x34, 0x6b, 0xdf, 0xa5, 0x14, 0xa4, 0x0, 0xb3, 0x42, 0x8c, 0xe5, 0x38, 0x37, 0xb4, 0x14, 0x3d, 0xd2, 0xda, 0xb4, 0x3d, 0xa2, 0x68, 0xe3, 0xc0, 0xcc, 0x35, 0x8a, 0x9e, 0x86, 0x4c, 0xa7, 0x15, 0x85, 0x9d, 0x6c, 0xb6, 0x13, 0x16, 0xe8, 0x54, 0x78, 0xbc, 0x8e, 0x60, 0x86, 0xd7, 0xd1, 0x17, 0xd3, 0x37, 0x6e, 0x48, 0x30, 0x4f, 0x70, 0x81, 0xbe, 0xed, 0x97, 0xd1, 0xfe, 0x6d, 0x44, 0xf7, 0xed, 0xa7, 0x63, 0x39, 0x79, 0x8c, 0xf6, 0xef, 0x8b, 0xe8, 0x61, 0xe6, 0x8d, 0x55, 0x5b, 0xae, 0x9e, 0x62, 0x3e, 0x1c, 0xd1, 0x3b, 0xf7, 0x9b, 0xc7, 0xfb, 0x9b, 0xab, 0x46, 0xcd, 0xab, 0x4b, 0xcd, 0xfd, 0x3b, 0x11, 0x1d, 0xe, 0x76, 0xf5, 0xc5, 0x2b, 0xe5, 0xf3, 0x67, 0x49, 0xcf, 0xcb, 0x2b, 0x8f, 0xea, 0xee, 0xe0, 0x10, 0xd1, 0xf0, 0xb2, 0x58, 0xb, 0x61, 0x75, 0xd6, 0x26, 0xcd, 0x56, 0x43, 0x58, 0x2b, 0x5e, 0x86, 0x88, 0x4e, 0x63, 0x33, 0x84, 0xf7, 0x1f, 0x26, 0xd5, 0x87, 0xf7, 0x61, 0x68, 0xc6, 0x29, 0xa2, 0x73, 0xdb, 0x5e, 0x2d, 0x57, 0x1f, 0xab, 0x56, 0xcb, 0xab, 0xed, 0x5c, 0xfe, 0xc4, 0x5d, 0xf1, 0x27, 0x1a, 0x8f, 0xba, 0x8d, 0xd7, 0xa0, 0x9a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char progress_bar_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0x27, 0x27, 0x27, 0xe1, 0x1d, 0x66, 0x4d, 0x0, 0x0, 0x0, 0xc, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xb7, 0x4a, 0xbe, 0x33, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x10, 0x95, 0xb2, 0xd, 0x2c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x44, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xc5, 0xcf, 0x31, 0x16, 0x0, 0x10, 0xc, 0x44, 0xc1, 0x4d, 0x84, 0x4, 0xc1, 0xfd, 0x6f, 0xab, 0xc9, 0x53, 0x70, 0x0, 0x53, 0x6e, 0xb5, 0x1f, 0x20, 0x4e, 0x12, 0x12, 0x13, 0x40, 0xb9, 0xa8, 0x5, 0x2d, 0x99, 0xc0, 0xb5, 0x75, 0xf, 0xbd, 0x55, 0x86, 0xe8, 0x98, 0x2b, 0xcc, 0xa1, 0x2, 0x31, 0x5f, 0x87, 0xdb, 0xbf, 0xe1, 0x3e, 0xf6, 0x5c, 0x7f, 0xe2, 0xee, 0xfc, 0xd, 0x60, 0x3b, 0xa, 0x1d, 0x9e, 0x6a, 0x29, 0x33, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0x43, 0x65, 0x7d, 0x95, 0x0, 0x0, 0x0, 0xc, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xb7, 0x4a, 0xbe, 0x33, 0x0, 0x0, 0x0, 0x35, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x9f, 0xe, 0x66, 0xb4, 0x33, 0x7a, 0xb4, 0x1b, 0x0, 0x19, 0x7f, 0x3b, 0x28, 0x64, 0xc0, 0xd, 0x84, 0x5b, 0x1, 0xb7, 0x14, 0xee, 0xc, 0x0, 0xcf, 0x9d, 0x26, 0xff, 0xba, 0xcb, 0x90, 0x39, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char progress_fill_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x26, 0x78, 0x80, 0xa6, 0xcf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x60, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x78, 0xc0, 0x8, 0x63, 0x38, 0x58, 0x7c, 0xde, 0xf8, 0x45, 0xc, 0xc2, 0xe6, 0x79, 0xc5, 0xeb, 0x7f, 0xe0, 0x4, 0x9a, 0x2, 0xe3, 0x97, 0x1f, 0xb9, 0xff, 0x70, 0x43, 0xd8, 0x2c, 0x5f, 0xf9, 0xbf, 0x9e, 0x15, 0x87, 0xb2, 0x61, 0xa, 0xbe, 0x88, 0xfd, 0x81, 0x1b, 0xfb, 0x87, 0xfb, 0xb, 0x37, 0x8c, 0xcd, 0x44, 0xc8, 0xd, 0x54, 0x54, 0xc0, 0xf3, 0x8a, 0xe5, 0x2b, 0x8c, 0xcd, 0xf2, 0x95, 0xe7, 0x15, 0x86, 0x2, 0x5e, 0x7f, 0xfe, 0xaf, 0xec, 0xc, 0x10, 0xc8, 0xff, 0x95, 0xd7, 0x9f, 0xe6, 0x1, 0x4c, 0x2, 0x0, 0x0, 0x68, 0x3f, 0x16, 0xd7, 0xea, 0x7c, 0xdd, 0x1a, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0x4c, 0xc0, 0xc1, 0xc2, 0xf8, 0xa5, 0xfa, 0x7f, 0x8, 0x34, 0x7e, 0xe9, 0x60, 0x81, 0xa1, 0xc0, 0xf8, 0xa5, 0xca, 0x17, 0x85, 0xff, 0x10, 0xa8, 0xf2, 0xc5, 0xf8, 0x25, 0x86, 0x2, 0x75, 0xa0, 0x4, 0x1c, 0x2, 0x4d, 0xa1, 0xbf, 0x2, 0x4c, 0x47, 0x12, 0xf6, 0xe6, 0x20, 0x2, 0x0, 0x78, 0x21, 0x45, 0x61, 0x7f, 0xe2, 0xad, 0xaf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char radio_checked_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xa, 0x69, 0x4, 0xd4, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x16, 0x7c, 0xd1, 0xa8, 0x19, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x69, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x6d, 0x8f, 0xdb, 0xe, 0xc0, 0x20, 0x8, 0x43, 0xdd, 0xc5, 0x3b, 0x9d, 0xa8, 0xec, 0xff, 0x7f, 0x75, 0x6a, 0x96, 0x2c, 0x8b, 0xf6, 0xad, 0x27, 0x14, 0x8a, 0x52, 0x2b, 0x69, 0x63, 0x9d, 0xb3, 0x46, 0xbf, 0x76, 0xf3, 0x21, 0x12, 0x40, 0x31, 0xf8, 0x7d, 0x0, 0x7f, 0x35, 0xdb, 0x45, 0x97, 0x1f, 0xf3, 0x81, 0x90, 0x38, 0x67, 0x4e, 0xa0, 0xd0, 0x53, 0x26, 0x22, 0x95, 0x2a, 0x52, 0x4b, 0x42, 0x34, 0xd, 0x58, 0x2, 0xd7, 0xbb, 0xa9, 0x32, 0xc8, 0x36, 0xe0, 0x80, 0x2c, 0x1d, 0x48, 0x6, 0xdc, 0xa, 0x4c, 0x91, 0x69, 0xe9, 0x74, 0x76, 0x2a, 0xa6, 0x8e, 0xaf, 0xfa, 0xb9, 0x7e, 0xee, 0xaf, 0x7, 0xb9, 0xfb, 0x8, 0xe7, 0x90, 0x1c, 0x65, 0x49, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x42, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xd1, 0xa7, 0xf5, 0xaa, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x4f, 0x55, 0x2, 0x43, 0x31, 0x8, 0x4b, 0xe8, 0x6a, 0xf7, 0xbf, 0xeb, 0xc, 0x9b, 0x6b, 0x1f, 0x9f, 0xc4, 0x89, 0xbf, 0xbb, 0x3f, 0x2a, 0x49, 0x64, 0xa6, 0x3e, 0x1e, 0x1c, 0x7c, 0x3e, 0xf2, 0x14, 0xb7, 0xc7, 0xac, 0xf1, 0x10, 0xa6, 0xe8, 0x1, 0x44, 0xad, 0x42, 0xb9, 0x33, 0x22, 0x43, 0x95, 0x68, 0x55, 0xa4, 0xdc, 0x1f, 0x1e, 0xa1, 0x67, 0xa2, 0x57, 0x96, 0x22, 0x0, 0xc2, 0x3d, 0xf5, 0x44, 0x8c, 0x8a, 0x5d, 0x21, 0x80, 0x74, 0x83, 0x1e, 0x97, 0xc7, 0x22, 0x59, 0x4c, 0xd7, 0xd8, 0xb5, 0x18, 0x4a, 0x7b, 0x57, 0x57, 0xdb, 0x1a, 0xf7, 0x77, 0x17, 0x3a, 0x56, 0x4e, 0x11, 0x6f, 0x82, 0x20, 0xde, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char radio_unchecked_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xff, 0xff, 0xff, 0xbd, 0x7d, 0x89, 0x66, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xe, 0x6f, 0xbd, 0x30, 0x4f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x4a, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x80, 0xb0, 0x8a, 0xf6, 0x54, 0x10, 0x2d, 0xb9, 0xfa, 0xcc, 0x99, 0x5d, 0x93, 0x80, 0x8c, 0xb9, 0x67, 0x80, 0xe0, 0x26, 0x3, 0x3, 0xeb, 0x1a, 0x10, 0xe3, 0x54, 0x0, 0x3, 0xdb, 0x1e, 0x10, 0xe3, 0x74, 0x2, 0x3, 0xfb, 0x19, 0x30, 0x28, 0x60, 0xe0, 0x80, 0x30, 0x1a, 0x10, 0xc, 0xb8, 0x14, 0x5c, 0x31, 0x5c, 0x3b, 0xdc, 0x40, 0x6, 0x4b, 0x90, 0x15, 0x53, 0x90, 0x2d, 0x85, 0x2, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xc4, 0xfc, 0x38, 0x7b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0x2b, 0x6e, 0xf2, 0xbf, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x2, 0x61, 0x15, 0xed, 0xa9, 0x20, 0x5a, 0x72, 0xf5, 0x99, 0x33, 0xbb, 0x26, 0x1, 0x19, 0x73, 0xcf, 0x0, 0xc1, 0x4d, 0x6, 0x6, 0xd6, 0x35, 0x20, 0xc6, 0xa9, 0x0, 0x6, 0xb6, 0x3d, 0x20, 0xc6, 0xe9, 0x4, 0x6, 0xf6, 0x33, 0x60, 0x50, 0xc0, 0xc0, 0x1, 0x61, 0x34, 0xc0, 0x19, 0x70, 0x29, 0xb8, 0x62, 0xb8, 0x76, 0x84, 0x81, 0xc, 0x96, 0x20, 0x2b, 0xa6, 0xc0, 0x2d, 0x45, 0x0, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xb4, 0x84, 0xb6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char reference_border_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xf, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xd1, 0xd1, 0xff, 0xb7, 0xb7, 0xff, 0x41, 0x41, 0xff, 0xff, 0xff, 0xd5, 0xfa, 0x24, 0x40, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x4, 0x8f, 0x68, 0xd9, 0x51, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x27, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x50, 0x32, 0x6, 0x3, 0x25, 0x6, 0x5, 0x6, 0x30, 0x60, 0x62, 0x30, 0x10, 0x4, 0x3, 0x66, 0x6, 0x3, 0x1, 0x90, 0x0, 0x23, 0x2d, 0x18, 0x30, 0x2b, 0xe0, 0x96, 0xc2, 0x9c, 0x1, 0x0, 0x5, 0x29, 0x7, 0xb, 0xf6, 0x43, 0xc2, 0xd4, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x2, 0x3, 0x0, 0x0, 0x0, 0x62, 0x9d, 0x17, 0xf2, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0xff, 0xd1, 0xd1, 0xff, 0xb7, 0xb7, 0xff, 0x41, 0x41, 0x2b, 0x2, 0x77, 0xea, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x25, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x58, 0xff, 0xff, 0xff, 0x2f, 0x86, 0x6, 0x6, 0x6, 0x26, 0x86, 0xa3, 0xa1, 0xa1, 0xc1, 0xc, 0x47, 0x18, 0x18, 0x84, 0x49, 0x22, 0xc0, 0xda, 0xc0, 0x6, 0x80, 0x8d, 0x2, 0x0, 0x36, 0x2b, 0x14, 0x3d, 0x85, 0x39, 0x85, 0x31, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x48, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xff, 0xff, 0xff, 0x34, 0x3f, 0xa6, 0x65, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x17, 0xb, 0xd6, 0x98, 0x8f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x5c, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0x8e, 0x49, 0xe, 0xc0, 0x20, 0xc, 0x3, 0x3, 0x61, 0x9, 0x3b, 0x61, 0xfb, 0xff, 0x53, 0x4b, 0x5b, 0x55, 0x15, 0x73, 0x1b, 0xc9, 0xb2, 0xd, 0x20, 0x24, 0x2a, 0xad, 0x15, 0x4a, 0x1, 0x20, 0x8c, 0x25, 0xc7, 0xec, 0xc8, 0x1a, 0x1, 0xd2, 0x87, 0xd6, 0xc7, 0xe8, 0x2d, 0x78, 0x9, 0x48, 0x6d, 0xae, 0xcd, 0x6c, 0x84, 0xa0, 0x62, 0x5f, 0xf, 0x3d, 0x2a, 0x48, 0x3c, 0x5e, 0x19, 0x9c, 0x4e, 0x39, 0x62, 0x47, 0x41, 0x2e, 0x5f, 0x75, 0xc9, 0x7b, 0xb4, 0x52, 0x64, 0x8e, 0x54, 0xcd, 0x7d, 0xe1, 0xbf, 0x73, 0x1, 0x30, 0x2f, 0x7, 0x53, 0x16, 0x34, 0xbd, 0xfa, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x14, 0xee, 0x69, 0x20, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x55, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8e, 0x45, 0x2, 0x80, 0x50, 0x10, 0x42, 0xc1, 0xee, 0xfb, 0x5f, 0xd4, 0xd6, 0xdf, 0xfd, 0x36, 0xd3, 0x3, 0x4, 0xd, 0x90, 0x6, 0xb2, 0x25, 0x39, 0xe0, 0xd2, 0xf9, 0xcb, 0x6a, 0x60, 0x6f, 0x27, 0xb7, 0xbc, 0x58, 0xb7, 0x53, 0x4d, 0x0, 0xf2, 0x3f, 0x5e, 0x36, 0x43, 0x5f, 0xc3, 0xf0, 0xdf, 0x17, 0xd7, 0xa6, 0xae, 0x60, 0x10, 0xff, 0x57, 0x16, 0xc5, 0x5a, 0xf1, 0x60, 0xe3, 0xe7, 0x5f, 0x37, 0x46, 0x74, 0xba, 0x9a, 0x16, 0xef, 0x37, 0x1c, 0x6f, 0x61, 0x47, 0x1, 0xa5, 0xc7, 0x32, 0x47, 0x38, 0x12, 0x92, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_down_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_down_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x33, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xf1, 0x33, 0x66, 0x2, 0x1, 0x2a, 0xa3, 0x73, 0xe6, 0xcc, 0x19, 0x10, 0x35, 0x40, 0x1, 0x8, 0xa3, 0x73, 0x6, 0x1, 0x73, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0x5a, 0xfa, 0x3d, 0xf9, 0xfa, 0xe2, 0x64, 0xe2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_left_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x2e, 0x28, 0xa3, 0x7b, 0xf7, 0x6e, 0x8, 0xa3, 0xe7, 0xcc, 0x19, 0xa8, 0x14, 0x9c, 0xd1, 0x7b, 0x17, 0xa6, 0xfd, 0x1d, 0x86, 0x81, 0x60, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0xcc, 0x4e, 0x3f, 0xd1, 0x4, 0x90, 0xbf, 0x60, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x3e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x2e, 0x28, 0xa3, 0x7b, 0xf7, 0x6e, 0x8, 0xa3, 0xe7, 0xcc, 0x19, 0xa8, 0x14, 0x9c, 0xd1, 0x7b, 0x17, 0xa6, 0xfd, 0x1d, 0x86, 0x81, 0x60, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0xcc, 0x4e, 0x3f, 0xd1, 0x4, 0x90, 0xbf, 0x60, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_left_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0x2a, 0x13, 0xff, 0x12, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x10, 0x95, 0xb2, 0xd, 0x2c, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x85, 0xcf, 0xcb, 0xe, 0x80, 0x20, 0xc, 0x44, 0xd1, 0xa2, 0x96, 0x47, 0x7, 0xe4, 0xff, 0xff, 0x16, 0xdc, 0x90, 0xe, 0xc6, 0x78, 0x97, 0x27, 0x69, 0xd3, 0x8a, 0x4, 0x75, 0x85, 0x43, 0x62, 0xca, 0xae, 0x14, 0x45, 0x33, 0xa5, 0xdf, 0x50, 0xa, 0x83, 0x99, 0x11, 0xa0, 0xa2, 0x7a, 0x0, 0xd0, 0xe0, 0xa1, 0x3d, 0xd1, 0xc8, 0x3d, 0xe3, 0xa5, 0xbd, 0x6f, 0x30, 0xe5, 0xef, 0xb0, 0x5, 0xaf, 0xe7, 0x4e, 0x7e, 0xff, 0x1a, 0xb, 0x26, 0x7, 0xac, 0xd9, 0xa3, 0x51, 0xe3, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0x58, 0xf9, 0x63, 0x6a, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x42, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x19, 0x33, 0xa1, 0x8c, 0xae, 0x55, 0x50, 0xc6, 0x9e, 0x3d, 0x10, 0x46, 0xf7, 0xee, 0xdb, 0x10, 0x46, 0xef, 0xdd, 0xbb, 0x50, 0xa9, 0x77, 0xef, 0xa0, 0x8c, 0xfe, 0x7f, 0x30, 0xed, 0xff, 0x81, 0xc, 0x4c, 0x93, 0x11, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfe, 0x97, 0x40, 0xa0, 0xa6, 0x84, 0xb1, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_right_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x18, 0x33, 0x61, 0x8c, 0x59, 0x2b, 0xa0, 0x8c, 0x5d, 0xab, 0xa0, 0x8c, 0xdd, 0xbb, 0x77, 0x40, 0x18, 0x67, 0xce, 0x9c, 0x80, 0x31, 0xa0, 0x52, 0x77, 0x6f, 0x40, 0x19, 0xef, 0x30, 0xc, 0x84, 0x30, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfd, 0x36, 0x40, 0x93, 0xf1, 0x83, 0x5f, 0xf2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0x59, 0x59, 0x59, 0x8e, 0x47, 0x76, 0xf1, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0x51, 0x18, 0x33, 0x61, 0x8c, 0x59, 0x2b, 0xa0, 0x8c, 0x5d, 0xab, 0xa0, 0x8c, 0xdd, 0xbb, 0x77, 0x40, 0x18, 0x67, 0xce, 0x9c, 0x80, 0x31, 0xa0, 0x52, 0x77, 0x6f, 0x40, 0x19, 0xef, 0x30, 0xc, 0x84, 0x30, 0xe0, 0x96, 0x1a, 0x42, 0x9c, 0x21, 0x2, 0x0, 0xfd, 0x36, 0x40, 0x93, 0xf1, 0x83, 0x5f, 0xf2, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_right_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0x59, 0x59, 0x59, 0x56, 0xec, 0x9e, 0xdc, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x11, 0xe2, 0xb5, 0x3d, 0xba, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x85, 0xcf, 0xcb, 0xe, 0x80, 0x30, 0x8, 0x44, 0x51, 0xaa, 0xd2, 0x7, 0xb4, 0xd2, 0xff, 0xff, 0xda, 0xea, 0x6e, 0x46, 0x63, 0xbc, 0xcb, 0x93, 0x40, 0x40, 0x24, 0x29, 0x94, 0x36, 0xc9, 0xa5, 0x42, 0x25, 0x8b, 0x56, 0x4a, 0xbf, 0xa0, 0xb5, 0x7, 0x98, 0x19, 0x83, 0x77, 0xef, 0xc, 0x3e, 0xdc, 0x11, 0xc6, 0x1d, 0xc2, 0x79, 0x45, 0x23, 0x11, 0xc1, 0x4b, 0xe7, 0xfc, 0x3b, 0xc, 0xe0, 0xf5, 0xdc, 0xce, 0xef, 0x1f, 0xb, 0xc, 0x30, 0x7, 0xaf, 0x1f, 0x5b, 0x76, 0x12, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc6, 0xc6, 0xc6, 0xc7, 0xc7, 0xc7, 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0x2e, 0x3d, 0xb1, 0x1e, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xc8, 0x31, 0x16, 0x2, 0x20, 0x10, 0x43, 0xc1, 0xe4, 0x83, 0xdc, 0xff, 0xb8, 0x88, 0xf, 0x57, 0xb, 0x8b, 0x80, 0x53, 0xe, 0xf2, 0x23, 0x18, 0xc6, 0x68, 0x61, 0x74, 0xca, 0xa, 0x2e, 0x74, 0xf9, 0x85, 0xfd, 0x17, 0x5c, 0x81, 0xfb, 0x11, 0x2a, 0xaa, 0x65, 0x80, 0x20, 0xc3, 0x5f, 0xaf, 0x2b, 0x96, 0xce, 0x78, 0xea, 0x88, 0x39, 0x95, 0x91, 0x70, 0x29, 0x94, 0xd9, 0x6b, 0x87, 0xf5, 0xfe, 0x0, 0xc6, 0xa7, 0x1b, 0x66, 0x7b, 0x42, 0xf1, 0x14, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_up_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x2d, 0x2c, 0x2f, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0x38, 0x36, 0x3a, 0xc3, 0xc3, 0xc3, 0x59, 0x59, 0x59, 0xb3, 0x52, 0xf2, 0x5, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x8, 0xfe, 0x9, 0xd, 0x19, 0x4a, 0xb6, 0xc1, 0xe6, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_button_up_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa, 0x68, 0xd0, 0xf4, 0x56, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x21, 0x50, 0x4c, 0x54, 0x45, 0x3d, 0x3b, 0x3f, 0x60, 0x5d, 0x62, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x3d, 0x3b, 0x3f, 0x65, 0x62, 0x67, 0x60, 0x5d, 0x62, 0x56, 0x53, 0x58, 0x4b, 0x49, 0x4e, 0xce, 0xce, 0xce, 0x59, 0x59, 0x59, 0xb8, 0xf5, 0x6d, 0x48, 0x0, 0x0, 0x0, 0x5, 0x74, 0x52, 0x4e, 0x53, 0x7, 0xfe, 0xc, 0x9, 0x1c, 0xda, 0x2b, 0xa5, 0x57, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc, 0x5, 0x3, 0x21, 0x86, 0xf4, 0xe, 0x30, 0x28, 0x63, 0x88, 0x80, 0x30, 0x5a, 0xb1, 0x33, 0x3a, 0x67, 0x40, 0x19, 0x33, 0x67, 0x42, 0x18, 0x9d, 0x33, 0x67, 0xce, 0x0, 0x33, 0x66, 0x2, 0x1, 0x2a, 0x3, 0x9f, 0x39, 0x10, 0x6, 0xdc, 0x52, 0x43, 0x88, 0x33, 0x44, 0x0, 0x59, 0xc8, 0x3d, 0xf9, 0xf, 0x68, 0xc5, 0xa9, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_grabber_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x60, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0x59, 0x61, 0x5b, 0x59, 0x61, 0x5a, 0x58, 0x60, 0x59, 0x57, 0x5f, 0x5a, 0x58, 0x60, 0x5a, 0x58, 0x60, 0x57, 0x56, 0x5e, 0x58, 0x56, 0x5e, 0x56, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x55, 0x53, 0x5b, 0x55, 0x53, 0x5b, 0x54, 0x53, 0x5b, 0x55, 0x54, 0x5c, 0x54, 0x52, 0x5a, 0x55, 0x53, 0x5b, 0x5a, 0x58, 0x60, 0x56, 0x54, 0x5c, 0x54, 0x53, 0x5a, 0x55, 0x53, 0x5b, 0x53, 0x51, 0x59, 0x52, 0x51, 0x59, 0x52, 0x50, 0x58, 0x51, 0x50, 0x58, 0x51, 0x4f, 0x57, 0x50, 0x4e, 0x56, 0x4f, 0x4d, 0x55, 0x50, 0x4f, 0x57, 0x54, 0x52, 0x5a, 0xff, 0xff, 0xff, 0xc7, 0x51, 0xc2, 0xf2, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2c, 0xb8, 0xf4, 0x2e, 0xf2, 0xb8, 0xf4, 0xf5, 0xf4, 0xf5, 0xb8, 0x2f, 0xf2, 0x2e, 0xb8, 0xf4, 0xb8, 0x66, 0xf6, 0xf7, 0x12, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1f, 0x5, 0xd, 0x10, 0xbd, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x50, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x7, 0x18, 0x99, 0x98, 0x85, 0x98, 0x18, 0x21, 0x6c, 0x16, 0x56, 0x61, 0x11, 0x11, 0x61, 0x56, 0x16, 0x30, 0x87, 0x4d, 0x54, 0xc, 0x8, 0x44, 0xd9, 0xc0, 0x1c, 0x76, 0x71, 0x9, 0x20, 0x10, 0xe7, 0x0, 0x73, 0x38, 0x25, 0xa5, 0x80, 0x40, 0x92, 0xb, 0xcc, 0xe1, 0x96, 0x90, 0x6, 0x2, 0x9, 0x6e, 0x30, 0x87, 0x87, 0x57, 0x4a, 0x46, 0x46, 0x96, 0x97, 0x7, 0x62, 0x1c, 0x1f, 0xbf, 0x80, 0x9c, 0x20, 0x1f, 0x5e, 0xdb, 0x1, 0x23, 0xfd, 0x4, 0x11, 0x2d, 0x48, 0xcb, 0xd2, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x5d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0x59, 0x61, 0x5b, 0x59, 0x61, 0x5a, 0x58, 0x60, 0x59, 0x57, 0x5f, 0x5a, 0x58, 0x60, 0x5a, 0x58, 0x60, 0x57, 0x56, 0x5e, 0x58, 0x56, 0x5e, 0x56, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x57, 0x55, 0x5d, 0x55, 0x53, 0x5b, 0x55, 0x53, 0x5b, 0x54, 0x53, 0x5b, 0x55, 0x54, 0x5c, 0x54, 0x52, 0x5a, 0x55, 0x53, 0x5b, 0x5a, 0x58, 0x60, 0x56, 0x54, 0x5c, 0x54, 0x53, 0x5a, 0x55, 0x53, 0x5b, 0x53, 0x51, 0x59, 0x52, 0x51, 0x59, 0x52, 0x50, 0x58, 0x51, 0x50, 0x58, 0x51, 0x4f, 0x57, 0x50, 0x4e, 0x56, 0x4f, 0x4d, 0x55, 0x50, 0x4f, 0x57, 0x54, 0x52, 0x5a, 0xae, 0x55, 0xff, 0xf7, 0x0, 0x0, 0x0, 0x12, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x2c, 0xb8, 0xf4, 0x2e, 0xf2, 0xb8, 0xf4, 0xf5, 0xf4, 0xf5, 0xb8, 0x2f, 0xf2, 0x2e, 0xb8, 0xf4, 0xb8, 0x66, 0xf6, 0xf7, 0x12, 0x0, 0x0, 0x0, 0x48, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x64, 0xc7, 0xb1, 0x11, 0x80, 0x40, 0x8, 0x45, 0x41, 0xff, 0x83, 0x2, 0xe, 0xfb, 0x2f, 0x13, 0xe2, 0xf3, 0x6, 0x12, 0x1d, 0x37, 0x5b, 0xae, 0x97, 0x5f, 0x84, 0xdd, 0x68, 0xe2, 0x1e, 0x41, 0xb8, 0x77, 0x58, 0x6, 0xb6, 0xe8, 0x88, 0xd1, 0xe1, 0x93, 0xad, 0x63, 0xab, 0xa3, 0x3a, 0xa3, 0x26, 0xa9, 0x4a, 0x52, 0xf9, 0xc, 0x62, 0xcf, 0xa7, 0x8f, 0x1f, 0x1e, 0xbd, 0xff, 0x84, 0xee, 0x2, 0x0, 0x54, 0x76, 0x10, 0x19, 0x1e, 0xd7, 0x1d, 0x9b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_grabber_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x97, 0xd0, 0xdf, 0x92, 0xcb, 0xdc, 0x84, 0xbb, 0xd4, 0x92, 0xca, 0xdc, 0x95, 0xd0, 0xdd, 0x83, 0xbb, 0xd3, 0x8b, 0xc8, 0xd7, 0x79, 0xb5, 0xcb, 0x78, 0xb4, 0xca, 0x73, 0xb0, 0xc7, 0x73, 0xb0, 0xc7, 0x7b, 0xc0, 0xcf, 0x79, 0xc5, 0xd1, 0x6b, 0xae, 0xc1, 0x75, 0xc6, 0xcf, 0x70, 0xbc, 0xca, 0x64, 0xa6, 0xbc, 0x71, 0xbc, 0xc9, 0x82, 0xba, 0xd4, 0x6a, 0xa2, 0xc6, 0x62, 0x9a, 0xc2, 0x61, 0x9a, 0xc1, 0x68, 0x9f, 0xc2, 0x5d, 0x92, 0xbb, 0x5c, 0x92, 0xb8, 0x58, 0x8d, 0xb6, 0x59, 0x8e, 0xb3, 0x56, 0x89, 0xb0, 0x5c, 0x91, 0xb2, 0x53, 0x84, 0xa9, 0x58, 0x8f, 0xae, 0x54, 0x83, 0xa4, 0x57, 0x8e, 0xad, 0x64, 0xa5, 0xba, 0xff, 0xff, 0xff, 0xbb, 0x65, 0x65, 0x27, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x25, 0xad, 0xf1, 0xad, 0x27, 0xef, 0xad, 0xf1, 0xf3, 0xf1, 0xf3, 0xad, 0x28, 0xef, 0x27, 0xad, 0xf2, 0xad, 0xcd, 0x8a, 0x27, 0xfe, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x23, 0x2a, 0x62, 0x6c, 0x3a, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x50, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x7, 0x18, 0x99, 0x98, 0x85, 0x59, 0x18, 0x21, 0x6c, 0x56, 0x36, 0x11, 0x51, 0x31, 0x11, 0x36, 0x56, 0x30, 0x87, 0x5d, 0x5c, 0x2, 0x8, 0xc4, 0xd9, 0xc1, 0x1c, 0xe, 0x49, 0x29, 0x20, 0x90, 0xe4, 0x4, 0x73, 0xb8, 0xa4, 0x65, 0x80, 0x40, 0x9a, 0x1b, 0xcc, 0xe1, 0x91, 0x95, 0x3, 0x2, 0x59, 0x1e, 0x30, 0x87, 0x97, 0x4f, 0x5e, 0x41, 0x41, 0x91, 0x8f, 0x17, 0x62, 0x1c, 0xbf, 0x80, 0xa0, 0x92, 0x10, 0x3f, 0x5e, 0xdb, 0x1, 0x41, 0x87, 0x4, 0x7d, 0x15, 0xc4, 0xfd, 0x6a, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x69, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x97, 0xd0, 0xdf, 0x92, 0xcb, 0xdc, 0x84, 0xbb, 0xd4, 0x92, 0xca, 0xdc, 0x95, 0xd0, 0xdd, 0x83, 0xbb, 0xd3, 0x8b, 0xc8, 0xd7, 0x79, 0xb5, 0xcb, 0x78, 0xb4, 0xca, 0x73, 0xb0, 0xc7, 0x73, 0xb0, 0xc7, 0x7b, 0xc0, 0xcf, 0x79, 0xc5, 0xd1, 0x6b, 0xae, 0xc1, 0x75, 0xc6, 0xcf, 0x70, 0xbc, 0xca, 0x64, 0xa6, 0xbc, 0x71, 0xbc, 0xc9, 0x82, 0xba, 0xd4, 0x6a, 0xa2, 0xc6, 0x62, 0x9a, 0xc2, 0x61, 0x9a, 0xc1, 0x68, 0x9f, 0xc2, 0x5d, 0x92, 0xbb, 0x5c, 0x92, 0xb8, 0x58, 0x8d, 0xb6, 0x59, 0x8e, 0xb3, 0x56, 0x89, 0xb0, 0x5c, 0x91, 0xb2, 0x53, 0x84, 0xa9, 0x58, 0x8f, 0xae, 0x54, 0x83, 0xa4, 0x57, 0x8e, 0xad, 0x64, 0xa5, 0xba, 0x17, 0x3b, 0xfc, 0x67, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x25, 0xad, 0xf1, 0xad, 0x27, 0xef, 0xad, 0xf1, 0xf3, 0xf1, 0xf3, 0xad, 0x28, 0xef, 0x27, 0xad, 0xf2, 0xad, 0xcd, 0x8a, 0x27, 0xfe, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x75, 0xc7, 0xa5, 0x1, 0x3, 0x1, 0x0, 0x4, 0xc1, 0xdd, 0xb, 0x9a, 0x60, 0xff, 0x3d, 0x6, 0x54, 0xe0, 0x59, 0x3d, 0x8f, 0x9b, 0xb0, 0x66, 0x3, 0x98, 0xdc, 0xff, 0x35, 0x20, 0xec, 0x3c, 0x6b, 0xf5, 0xae, 0xff, 0x6c, 0xda, 0xdc, 0x36, 0x31, 0xc7, 0x6f, 0xc9, 0x16, 0x8c, 0x40, 0x1d, 0xba, 0x64, 0x21, 0x42, 0xc0, 0x97, 0xc9, 0xe6, 0x25, 0x8, 0x5c, 0xf4, 0xf6, 0x2c, 0x5f, 0x8c, 0x39, 0x4c, 0x3, 0xfe, 0x9a, 0x10, 0x43, 0x82, 0xcf, 0x27, 0x93, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char scroll_grabber_pressed_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x6, 0x0, 0x0, 0x0, 0x56, 0x75, 0x5c, 0xe7, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xd, 0xd7, 0x0, 0x0, 0xd, 0xd7, 0x1, 0x42, 0x28, 0x9b, 0x78, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x0, 0x77, 0x77, 0x77, 0x2e, 0x69, 0x6e, 0x6b, 0x73, 0x63, 0x61, 0x70, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x9b, 0xee, 0x3c, 0x1a, 0x0, 0x0, 0x0, 0x66, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xcd, 0x91, 0xb1, 0xa, 0xc0, 0x20, 0x10, 0x43, 0x63, 0x71, 0xbf, 0x5f, 0x12, 0x9c, 0xfd, 0x1a, 0x3f, 0xcd, 0xa9, 0x83, 0xe0, 0x2f, 0x65, 0x2f, 0x9c, 0x8b, 0x83, 0x47, 0xed, 0x60, 0xbb, 0x34, 0xdb, 0x3d, 0x12, 0x48, 0x38, 0xa7, 0xaa, 0xd8, 0xd1, 0xb1, 0xe5, 0x7e, 0x13, 0xf0, 0xf3, 0xd1, 0x5a, 0xf3, 0x24, 0x23, 0x80, 0x34, 0x50, 0x11, 0x91, 0x1a, 0x42, 0xb8, 0x96, 0x1, 0x92, 0x51, 0x55, 0xf3, 0x84, 0x32, 0x49, 0x0, 0x38, 0x9f, 0x2a, 0x25, 0xdc, 0x65, 0xd8, 0xe7, 0xd1, 0x65, 0xe1, 0x31, 0xcc, 0x6c, 0x10, 0x91, 0x3a, 0x3a, 0x9b, 0xd1, 0xb3, 0xc7, 0xfd, 0xef, 0x71, 0x1d, 0x42, 0xe6, 0x21, 0x43, 0xf5, 0x2b, 0xd8, 0x6c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x8, 0x4, 0x0, 0x0, 0x0, 0xfc, 0x7c, 0x94, 0x6c, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x3a, 0xd8, 0xcf, 0xb2, 0xc1, 0x7d, 0xc3, 0x14, 0x20, 0x74, 0xdf, 0xcf, 0x82, 0x22, 0xb1, 0xc1, 0x7d, 0xfd, 0x2e, 0x8, 0xdc, 0xe0, 0x8e, 0x2a, 0x31, 0x5, 0x2e, 0x31, 0x85, 0x90, 0x4, 0xa6, 0x51, 0xb8, 0x2d, 0xa7, 0x36, 0x0, 0x0, 0x7b, 0xcd, 0x2b, 0x75, 0x45, 0x5e, 0xf8, 0x88, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char selection_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfb, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf6, 0xff, 0xf6, 0xf4, 0xff, 0x15, 0x15, 0x17, 0xff, 0x70, 0xc0, 0x21, 0x0, 0x0, 0x0, 0xe, 0x74, 0x52, 0x4e, 0x53, 0x6, 0xf, 0x16, 0x18, 0x2a, 0x3b, 0x40, 0x3c, 0x6, 0x3d, 0x44, 0x3e, 0x31, 0x25, 0x8, 0x3d, 0x16, 0xb4, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xe, 0x6f, 0xbd, 0x30, 0x4f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x6, 0x2, 0x23, 0x1, 0x6, 0x91, 0xb0, 0x34, 0x20, 0x48, 0x75, 0x64, 0x50, 0xef, 0x5c, 0x5, 0x4, 0x33, 0x8a, 0x18, 0xcc, 0xf6, 0xdc, 0x5, 0x82, 0xd3, 0xc9, 0xc, 0x66, 0x6b, 0x41, 0x8c, 0x5b, 0x94, 0x33, 0x60, 0x6, 0xc2, 0xad, 0x80, 0x5b, 0xa, 0x73, 0x6, 0x0, 0x45, 0x34, 0x48, 0x41, 0xa3, 0xc5, 0x91, 0x23, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfd, 0xfb, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf7, 0xff, 0xfd, 0xf6, 0xff, 0xf6, 0xf4, 0xff, 0x15, 0x15, 0x17, 0xff, 0x70, 0xc0, 0x21, 0x0, 0x0, 0x0, 0xe, 0x74, 0x52, 0x4e, 0x53, 0x6, 0xf, 0x16, 0x18, 0x2a, 0x3b, 0x40, 0x3c, 0x6, 0x3d, 0x44, 0x3e, 0x31, 0x25, 0x8, 0x3d, 0x16, 0xb4, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x6, 0x2, 0x23, 0x1, 0x6, 0x91, 0xb0, 0x34, 0x20, 0x48, 0x75, 0x64, 0x50, 0xef, 0x5c, 0x5, 0x4, 0x33, 0x8a, 0x18, 0xcc, 0xf6, 0xdc, 0x5, 0x82, 0xd3, 0xc9, 0xc, 0x66, 0x6b, 0x41, 0x8c, 0x5b, 0x94, 0x33, 0x60, 0x6, 0xc2, 0xad, 0x80, 0x5b, 0xa, 0x73, 0x6, 0x0, 0x45, 0x34, 0x48, 0x41, 0xa3, 0xc5, 0x91, 0x23, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char selection_oof_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0x15, 0x15, 0x17, 0xe9, 0x54, 0x1, 0x21, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xf, 0x18, 0xba, 0x0, 0xd9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x76, 0x1, 0x2, 0x23, 0x1, 0x6, 0xd1, 0xf4, 0xe, 0x20, 0x28, 0xb, 0x64, 0xd0, 0x5c, 0x7d, 0x6, 0x8, 0x76, 0x4d, 0x62, 0x70, 0xdf, 0xfb, 0xe, 0x8, 0x6e, 0x97, 0x30, 0x78, 0x9c, 0x3, 0x31, 0xde, 0xb4, 0x50, 0xca, 0x80, 0x1b, 0x8, 0xb7, 0x2, 0x6e, 0x29, 0xcc, 0x19, 0x0, 0x1a, 0x23, 0x52, 0x59, 0xa4, 0x2f, 0x3d, 0xa7, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xaf, 0xdf, 0x90, 0xa5, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x2f, 0x33, 0x4, 0x32, 0xde, 0xce, 0x64, 0xf4, 0x68, 0x53, 0x0, 0x32, 0xfe, 0xcd, 0xa0, 0x90, 0x1, 0x37, 0x10, 0x6e, 0x5, 0xdc, 0x52, 0xb8, 0x33, 0x0, 0xcc, 0x7, 0x26, 0xff, 0x1f, 0x38, 0x23, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char spinbox_updown_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xcd, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xe5, 0x53, 0x31, 0xe, 0x82, 0x40, 0x10, 0x9c, 0x5d, 0x22, 0x3e, 0x80, 0x86, 0xc4, 0x0, 0xe1, 0xf, 0x16, 0x5a, 0x58, 0xf9, 0x5, 0xe3, 0x13, 0xd0, 0xc2, 0xc4, 0xcf, 0xd8, 0xf0, 0x5, 0xe3, 0x1f, 0x2c, 0x2c, 0x6c, 0xf8, 0x1, 0xc5, 0x72, 0x85, 0x9, 0xd, 0xf, 0x10, 0x43, 0xce, 0x86, 0x82, 0xe0, 0xe9, 0x19, 0x8d, 0x95, 0x53, 0xce, 0xce, 0x6e, 0x26, 0x99, 0x59, 0xe0, 0x97, 0x10, 0x91, 0x95, 0x52, 0x2a, 0x79, 0xa5, 0xa1, 0x67, 0x83, 0xa2, 0x28, 0xa6, 0x0, 0x8e, 0x0, 0x98, 0x99, 0xe7, 0x61, 0x18, 0x9e, 0xde, 0x3e, 0x20, 0x22, 0x3e, 0x11, 0x65, 0x0, 0x46, 0x2d, 0x55, 0x3a, 0x8e, 0x33, 0xe, 0x82, 0xe0, 0xd2, 0xd7, 0x72, 0x9f, 0xc8, 0xb2, 0x6c, 0x0, 0x60, 0xdf, 0x59, 0x6, 0x0, 0xbf, 0x69, 0x9a, 0x43, 0x9e, 0xe7, 0x43, 0xeb, 0x1, 0xcf, 0xf3, 0x76, 0x44, 0x34, 0x33, 0x18, 0x9b, 0xb8, 0xae, 0x9b, 0x9a, 0x1c, 0xff, 0x3b, 0x1e, 0x62, 0x14, 0x91, 0x94, 0x88, 0x8c, 0xe5, 0x21, 0xa2, 0x34, 0x8a, 0xa2, 0x75, 0x97, 0x7b, 0x48, 0xa1, 0xaa, 0xaa, 0x8d, 0xd6, 0xda, 0x54, 0x9a, 0x73, 0x5d, 0xd7, 0x5b, 0xab, 0x83, 0xd6, 0xc5, 0xe7, 0x45, 0x2, 0x80, 0x38, 0x8e, 0x4b, 0xad, 0xf5, 0x2, 0xc0, 0x15, 0xc0, 0x8d, 0x99, 0x97, 0xa6, 0x65, 0x2b, 0x94, 0x52, 0x89, 0xed, 0x99, 0xbe, 0xc6, 0x1d, 0x31, 0x1f, 0x40, 0xdc, 0x74, 0x8a, 0x5b, 0xc1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0xdc, 0x4f, 0x7f, 0x98, 0x86, 0x47, 0xfa, 0x81, 0xe5, 0x83, 0x1f, 0xf, 0x7e, 0x3d, 0xb2, 0xc5, 0xa5, 0x5b, 0xe2, 0xc1, 0x93, 0x7, 0xff, 0x81, 0xf0, 0xf9, 0x63, 0x69, 0x2c, 0xd2, 0x67, 0x58, 0xef, 0x1f, 0x2, 0x4a, 0x42, 0xe0, 0xf1, 0xdb, 0xec, 0x98, 0xfa, 0x67, 0x2, 0x25, 0xe0, 0xf0, 0xe1, 0x2, 0x86, 0x41, 0x7, 0x30, 0x1d, 0x39, 0x3, 0xbf, 0x37, 0x8f, 0xdd, 0x66, 0x27, 0x29, 0xa0, 0x10, 0x4a, 0x2c, 0xa0, 0x41, 0x8d, 0x1b, 0x3c, 0x4c, 0x3, 0x46, 0x16, 0x69, 0x0, 0x0, 0x87, 0x2a, 0x58, 0xb5, 0x18, 0xe9, 0x80, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char submenu_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x7d, 0xca, 0x21, 0x12, 0x80, 0x20, 0x14, 0x45, 0xd1, 0xf7, 0x2d, 0x4, 0x36, 0x40, 0x63, 0xa8, 0xba, 0x1f, 0xbb, 0x9d, 0xe5, 0xb8, 0x0, 0xb3, 0xfb, 0xd1, 0xc, 0x8d, 0xd, 0x10, 0x48, 0xcf, 0x22, 0x6, 0xc7, 0xef, 0x6d, 0x77, 0xe6, 0x8, 0x0, 0xa4, 0x94, 0x88, 0x3b, 0x92, 0x4b, 0x8, 0x61, 0xeb, 0x3f, 0xe0, 0x95, 0x88, 0xac, 0x39, 0xe7, 0x49, 0x5, 0x0, 0x2c, 0xc9, 0xbd, 0x94, 0x62, 0x35, 0x0, 0x0, 0x63, 0x6b, 0x6d, 0xfd, 0x3, 0x4f, 0x1a, 0x38, 0x8d, 0x31, 0x51, 0x3, 0x55, 0x44, 0x66, 0xe7, 0x5c, 0xfd, 0x4, 0x24, 0xa3, 0xf7, 0xfe, 0xe8, 0x7f, 0x1, 0xe, 0xc2, 0x1e, 0x10, 0xa, 0xf0, 0x33, 0x4c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x2e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x78, 0xc0, 0xf0, 0xe0, 0x3f, 0x8, 0xde, 0x4f, 0x60, 0x0, 0x3, 0xb8, 0xc0, 0x83, 0x2f, 0xf, 0xb5, 0xe1, 0x2, 0x50, 0x78, 0xf5, 0x5, 0x37, 0xaa, 0xc0, 0xff, 0x87, 0xf3, 0x31, 0x4, 0x30, 0xb5, 0x60, 0x1a, 0x8a, 0x61, 0x2d, 0x0, 0xa6, 0x55, 0x4f, 0xb1, 0x91, 0xd6, 0xa7, 0xae, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x0, 0xaa, 0x8d, 0x23, 0x32, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0xc0, 0x4, 0xff, 0x23, 0xff, 0x8b, 0xfc, 0x17, 0xf9, 0x1f, 0x49, 0xac, 0x10, 0x13, 0x3, 0x3, 0x61, 0x53, 0xb0, 0x98, 0x80, 0xc, 0x0, 0xa8, 0x3e, 0x18, 0x31, 0xbe, 0x78, 0xfc, 0x7a, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x19, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xc0, 0x2, 0xfe, 0x47, 0xfe, 0x17, 0x1, 0xc2, 0x48, 0xd2, 0x84, 0x10, 0x2, 0x84, 0xb9, 0x98, 0x0, 0x0, 0xbf, 0x67, 0x1d, 0x5, 0x89, 0x9b, 0x48, 0x90, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_behind_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x5a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x2e, 0x36, 0x43, 0x40, 0x4d, 0x0, 0x0, 0x0, 0x43, 0x40, 0x4c, 0x3e, 0x3c, 0x47, 0x3e, 0x3b, 0x46, 0x31, 0x2f, 0x38, 0x2d, 0x2b, 0x33, 0x3f, 0x3c, 0x47, 0x35, 0x32, 0x3b, 0x5b, 0xb0, 0x1, 0xb7, 0x0, 0x0, 0x0, 0x18, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0xc, 0x4, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x77, 0xf3, 0x7, 0xef, 0xd3, 0x51, 0x5e, 0xca, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1d, 0xeb, 0x3, 0x71, 0x91, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x6e, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xb5, 0xcc, 0x49, 0xe, 0x80, 0x20, 0x10, 0x44, 0xd1, 0x2, 0x6c, 0x90, 0x49, 0x26, 0x27, 0xd4, 0xfb, 0x9f, 0x53, 0x63, 0x34, 0x2e, 0x58, 0xfb, 0x97, 0x2f, 0xa9, 0x2, 0x18, 0x17, 0x1d, 0x49, 0xa5, 0x24, 0x75, 0x82, 0x33, 0x80, 0xf5, 0xa4, 0x8d, 0x75, 0xde, 0x3b, 0x6b, 0x34, 0xf5, 0xc, 0x9c, 0x86, 0x10, 0x53, 0x2e, 0x25, 0xa7, 0x18, 0x6, 0xe2, 0x10, 0x3a, 0x8c, 0xd3, 0x5a, 0xaf, 0xd6, 0x69, 0xc, 0x5a, 0x60, 0x36, 0x71, 0xd9, 0xf6, 0xbb, 0x6d, 0x89, 0x66, 0x6, 0xd9, 0x74, 0xec, 0x4f, 0x47, 0xb2, 0x4, 0xe9, 0x72, 0x7d, 0xa1, 0x66, 0x27, 0xa1, 0x7c, 0xf9, 0xa0, 0x78, 0xd5, 0x42, 0x33, 0x69, 0x4e, 0xff, 0x80, 0x13, 0xce, 0x8, 0x12, 0xa9, 0x90, 0xd8, 0x47, 0x93, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x57, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x2e, 0x36, 0x43, 0x40, 0x4d, 0x0, 0x0, 0x0, 0x43, 0x40, 0x4c, 0x3e, 0x3c, 0x47, 0x3e, 0x3b, 0x46, 0x31, 0x2f, 0x38, 0x2d, 0x2b, 0x33, 0x3f, 0x3c, 0x47, 0x91, 0xf8, 0xc4, 0xb2, 0x0, 0x0, 0x0, 0x18, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x3, 0x5, 0x8, 0xa, 0xb, 0xc, 0x4, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x77, 0xf3, 0x7, 0xef, 0xd3, 0x51, 0x5e, 0xca, 0x0, 0x0, 0x0, 0x5a, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0x8c, 0x35, 0x2, 0x80, 0x30, 0x10, 0x4, 0x6f, 0x73, 0xc4, 0x53, 0xf3, 0xff, 0x3f, 0xe2, 0xee, 0x4e, 0x9d, 0xe9, 0x56, 0x41, 0xd8, 0xa1, 0x69, 0x7, 0xd0, 0x43, 0x72, 0x19, 0x3d, 0x37, 0x10, 0x6c, 0x1f, 0x8d, 0x6a, 0x0, 0x2b, 0x25, 0xc1, 0x20, 0xa2, 0x69, 0x98, 0xba, 0xb6, 0x45, 0x9a, 0x2b, 0xbd, 0xe9, 0xd5, 0x69, 0xda, 0x0, 0xa9, 0x94, 0x9f, 0x68, 0x7, 0xc5, 0xd2, 0x50, 0x4a, 0x69, 0x71, 0x18, 0x63, 0xb3, 0x18, 0x7a, 0x71, 0x2e, 0xa3, 0xfd, 0x1b, 0xff, 0xc9, 0xff, 0x34, 0x86, 0x31, 0x3, 0x12, 0xb2, 0x4c, 0x6a, 0xfb, 0x60, 0xc7, 0xdc, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_close_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xfa, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0xcd, 0x92, 0x5f, 0x4a, 0xc4, 0x30, 0x10, 0x87, 0xbf, 0xb1, 0xb9, 0xc2, 0x16, 0x7c, 0x6b, 0xc1, 0xa2, 0x85, 0x7a, 0x4, 0x2d, 0xfe, 0x39, 0xc4, 0x9e, 0x70, 0x4f, 0x61, 0xc5, 0x3d, 0x83, 0x5, 0x95, 0x4, 0xd2, 0x37, 0x5, 0x8f, 0x90, 0x94, 0xf1, 0xc5, 0x4a, 0x76, 0xcd, 0x22, 0xf8, 0xa2, 0xf3, 0x38, 0xc3, 0xef, 0x9b, 0xe4, 0x4b, 0xe0, 0x5f, 0x95, 0xf7, 0x7e, 0xed, 0x9c, 0x2b, 0xf, 0xcd, 0x9d, 0x73, 0xa5, 0xf7, 0x7e, 0x9d, 0xf6, 0x8e, 0xd2, 0xb0, 0x88, 0x6c, 0x8c, 0x31, 0x43, 0xe, 0xe2, 0x9c, 0x2b, 0x8d, 0x31, 0x83, 0x88, 0x6c, 0x52, 0xc8, 0x17, 0x20, 0xc6, 0x38, 0xa8, 0xea, 0x8, 0x74, 0xc6, 0x98, 0xed, 0x34, 0x4d, 0xc7, 0xcb, 0xcc, 0x5a, 0xbb, 0x2a, 0x8a, 0xe2, 0xe, 0xe8, 0x80, 0x17, 0xe0, 0x61, 0x99, 0x49, 0xba, 0xc5, 0x5a, 0xbb, 0xfa, 0xdc, 0x72, 0xe, 0x3c, 0x3, 0xd7, 0x21, 0x84, 0x98, 0xf6, 0x54, 0xf5, 0xaa, 0xae, 0xeb, 0xb7, 0x2c, 0x60, 0x1f, 0x22, 0x22, 0x56, 0x55, 0x23, 0xd0, 0xe6, 0xc2, 0x59, 0x40, 0x2, 0xd9, 0x8a, 0x48, 0xbb, 0x28, 0x50, 0xd5, 0x8b, 0xfd, 0xf0, 0x8e, 0x83, 0x9f, 0x4a, 0x44, 0xb2, 0xcb, 0xbe, 0x1, 0x92, 0x2b, 0xb4, 0xaa, 0x6a, 0x81, 0x27, 0xe0, 0x4, 0xb8, 0x4f, 0xc5, 0x66, 0x1, 0x19, 0x89, 0x97, 0x21, 0x84, 0x5e, 0x55, 0x1f, 0x81, 0xb3, 0x1c, 0x44, 0xe, 0x85, 0x53, 0x61, 0xb9, 0xd7, 0xa9, 0xaa, 0xea, 0x75, 0xe7, 0x4, 0xc6, 0x98, 0x1b, 0x11, 0xe9, 0x80, 0x31, 0xc6, 0xd8, 0xa7, 0xc2, 0x9a, 0xa6, 0x79, 0x9f, 0xe7, 0xf9, 0x16, 0x18, 0x81, 0x53, 0x55, 0xed, 0xb3, 0xa2, 0x7e, 0xf3, 0x95, 0xff, 0xbe, 0x3e, 0x0, 0xbd, 0x2c, 0x93, 0xec, 0xb, 0xe5, 0x4f, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xad, 0x90, 0x1, 0x6, 0xc0, 0x30, 0xc, 0x45, 0x77, 0x89, 0xd5, 0x76, 0xb3, 0x9e, 0x7b, 0x65, 0x63, 0xd, 0xf9, 0xbb, 0x48, 0x3b, 0xb3, 0x92, 0x54, 0x42, 0xb1, 0x5, 0x88, 0xf7, 0xc8, 0xcf, 0x9f, 0xfe, 0x1a, 0x8e, 0x14, 0xf4, 0x4e, 0x81, 0x63, 0x87, 0x51, 0x90, 0x28, 0x8, 0x46, 0x42, 0x51, 0x4a, 0x9e, 0x79, 0x43, 0xc5, 0x81, 0x55, 0x6f, 0xbc, 0x34, 0xdc, 0x2b, 0x2e, 0x16, 0xe5, 0x3a, 0xb1, 0xb, 0xb6, 0xca, 0x3, 0x2b, 0xb2, 0xc2, 0xbe, 0xf0, 0x66, 0x71, 0x4f, 0x70, 0x3b, 0x61, 0x14, 0x89, 0x26, 0x71, 0x5d, 0x6c, 0x9f, 0x1e, 0x17, 0x35, 0xae, 0xfa, 0xeb, 0xdc, 0x62, 0xc3, 0x84, 0x2d, 0x77, 0x22, 0xda, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_container_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x8a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0xff, 0xff, 0xff, 0xe5, 0x37, 0x10, 0x78, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x2d, 0xcd, 0xda, 0x41, 0x3d, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x93, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x65, 0xcf, 0x47, 0x12, 0x82, 0x40, 0x10, 0x5, 0xd0, 0x9e, 0xc8, 0x44, 0x92, 0x22, 0x41, 0x54, 0x44, 0x40, 0x14, 0xef, 0x7f, 0x3e, 0x7, 0x8a, 0xea, 0x85, 0xbe, 0xe5, 0xaf, 0xea, 0xf0, 0x1, 0x8, 0x65, 0x5c, 0xc8, 0x40, 0x70, 0x46, 0x9, 0x0, 0x89, 0x94, 0x36, 0xd6, 0x79, 0xef, 0xac, 0xd1, 0x2a, 0x22, 0x40, 0x55, 0x9c, 0x14, 0xa7, 0x4d, 0x91, 0xc4, 0x8a, 0x2, 0xd3, 0x69, 0x59, 0xd5, 0x9b, 0xaa, 0x4c, 0x35, 0x3, 0x6e, 0x9a, 0xfa, 0xbc, 0xab, 0x1b, 0xc3, 0x41, 0xd8, 0xf6, 0x82, 0x5a, 0x2b, 0x40, 0xba, 0xeb, 0xd, 0x5d, 0x9d, 0x4, 0xe9, 0xbb, 0x3b, 0xea, 0xfc, 0x1a, 0xf4, 0xf, 0xd4, 0xaf, 0x81, 0x1b, 0x46, 0x34, 0x84, 0x11, 0x61, 0xa7, 0x27, 0x9a, 0xc2, 0x52, 0x6e, 0xe6, 0x17, 0x9a, 0xc3, 0x59, 0xa6, 0xb3, 0xf1, 0xbd, 0x1b, 0xb3, 0xf0, 0x18, 0x55, 0xf9, 0x61, 0xf9, 0x6c, 0x96, 0x63, 0x1e, 0x5e, 0xff, 0x2b, 0xf7, 0x5b, 0xff, 0xb, 0x69, 0x5a, 0x14, 0xfa, 0x84, 0xf6, 0xc2, 0x8, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x87, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3c, 0x3a, 0x44, 0x56, 0x53, 0x61, 0x56, 0x52, 0x60, 0x47, 0x44, 0x52, 0x33, 0x31, 0x39, 0x47, 0x44, 0x50, 0x47, 0x44, 0x51, 0x52, 0x50, 0x5d, 0x51, 0x4f, 0x5d, 0x46, 0x42, 0x4e, 0x42, 0x3e, 0x4a, 0x41, 0x3e, 0x49, 0x51, 0x4e, 0x5b, 0x40, 0x3e, 0x48, 0x4f, 0x4c, 0x59, 0x3f, 0x3d, 0x47, 0x4e, 0x4a, 0x58, 0x3e, 0x3b, 0x46, 0x4b, 0x49, 0x55, 0x3c, 0x3a, 0x44, 0x4a, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x49, 0x46, 0x53, 0x3a, 0x38, 0x42, 0x47, 0x45, 0x50, 0x39, 0x37, 0x40, 0x47, 0x43, 0x50, 0x38, 0x35, 0x3f, 0x36, 0x34, 0x3e, 0x44, 0x42, 0x4d, 0x44, 0x41, 0x4c, 0x3f, 0x38, 0xaa, 0x5e, 0x0, 0x0, 0x0, 0x15, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xef, 0x77, 0xef, 0xed, 0xe8, 0xff, 0x76, 0xed, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x65, 0xcf, 0x45, 0x2, 0x84, 0x30, 0x14, 0x4, 0xd1, 0x2e, 0x1c, 0xee, 0x7f, 0xca, 0xd1, 0xed, 0x28, 0x8d, 0x4b, 0x92, 0x5a, 0xbe, 0xe8, 0x2f, 0xc4, 0x9c, 0x24, 0xcf, 0x15, 0x54, 0xab, 0x78, 0xee, 0x53, 0x30, 0x4a, 0x85, 0xa6, 0xfc, 0xf1, 0x87, 0x11, 0xb2, 0x9a, 0x15, 0x9a, 0x37, 0x13, 0x74, 0xce, 0xb4, 0xd4, 0x77, 0xcb, 0xe, 0xb4, 0x96, 0x99, 0x10, 0x34, 0x81, 0x42, 0x50, 0x21, 0x9d, 0x41, 0x23, 0xf8, 0xc, 0x56, 0xe1, 0x10, 0x9c, 0x40, 0x4e, 0xfe, 0x6e, 0x72, 0x96, 0x7e, 0xd7, 0xdf, 0x3f, 0xb3, 0x79, 0x90, 0xcd, 0xf1, 0xc4, 0x26, 0x1e, 0x8e, 0x78, 0xfc, 0x1, 0xf5, 0x61, 0x3f, 0x44, 0xe8, 0xf1, 0xdd, 0xba, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_current_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x9c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0x35, 0x32, 0x3b, 0x59, 0xdd, 0xd3, 0xff, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x33, 0x37, 0xd5, 0x7c, 0x5e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xa2, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x45, 0xcd, 0xd9, 0x12, 0x82, 0x30, 0xc, 0x40, 0xd1, 0x0, 0x2d, 0x4b, 0x5b, 0x36, 0x59, 0x44, 0x44, 0x44, 0xa4, 0x68, 0x59, 0x54, 0xfc, 0xff, 0x8f, 0x33, 0x30, 0x4c, 0x3d, 0x93, 0xa7, 0x3b, 0x93, 0x4, 0xc0, 0x30, 0x2d, 0x42, 0x6d, 0x44, 0x89, 0x65, 0x1a, 0x0, 0x86, 0xe3, 0x7a, 0x8c, 0xb, 0xdf, 0x17, 0x9c, 0x79, 0xae, 0x63, 0x80, 0xe9, 0x6, 0x61, 0x7c, 0xd8, 0xc4, 0x61, 0xe0, 0x9a, 0x60, 0x79, 0x51, 0x92, 0x66, 0x9b, 0x34, 0x89, 0x3c, 0xb, 0x8, 0xcb, 0xb3, 0xe3, 0x2e, 0xcb, 0x19, 0x1, 0xca, 0x8b, 0x93, 0x56, 0x70, 0xa, 0xb6, 0x28, 0xcf, 0x5a, 0x29, 0x6c, 0xb0, 0xfd, 0xea, 0xa2, 0x55, 0xfe, 0x1a, 0xea, 0xab, 0x56, 0xaf, 0x41, 0x34, 0x37, 0xad, 0xc1, 0x15, 0xca, 0xdb, 0xbb, 0xd6, 0xe2, 0x51, 0xc2, 0xba, 0x7f, 0xe8, 0xf0, 0x2d, 0x6, 0x29, 0xfb, 0x5e, 0xca, 0xc7, 0x53, 0xca, 0x3d, 0xa8, 0x61, 0x50, 0xc3, 0xa8, 0xc6, 0x41, 0xed, 0x61, 0x9a, 0xa6, 0x19, 0xbd, 0xe6, 0xf7, 0x1e, 0x3e, 0xcb, 0x82, 0x83, 0xbe, 0x18, 0x7e, 0xa1, 0xe5, 0x17, 0x1f, 0xcf, 0x5d, 0x82, 0x6b, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3f, 0x3d, 0x48, 0x5b, 0x58, 0x66, 0x5b, 0x57, 0x65, 0x57, 0x54, 0x62, 0x55, 0x53, 0x62, 0x4a, 0x46, 0x52, 0x46, 0x41, 0x4e, 0x45, 0x41, 0x4d, 0x55, 0x52, 0x60, 0x44, 0x41, 0x4c, 0x53, 0x50, 0x5e, 0x43, 0x40, 0x4b, 0x52, 0x4e, 0x5d, 0x41, 0x3e, 0x4a, 0x4f, 0x4d, 0x5a, 0x3f, 0x3d, 0x48, 0x4e, 0x4b, 0x59, 0x3e, 0x3c, 0x47, 0x4d, 0x4a, 0x58, 0x3d, 0x3b, 0x46, 0x4b, 0x49, 0x54, 0x3c, 0x3a, 0x44, 0x4b, 0x47, 0x54, 0x3b, 0x39, 0x43, 0x3b, 0x39, 0x42, 0x3b, 0x38, 0x43, 0x3b, 0x38, 0x42, 0x3a, 0x37, 0x41, 0x39, 0x37, 0x41, 0x3a, 0x38, 0x41, 0x39, 0x36, 0x3f, 0x38, 0x36, 0x3f, 0x39, 0x36, 0x40, 0x38, 0x36, 0x40, 0x37, 0x35, 0x3e, 0x37, 0x34, 0x3e, 0x36, 0x35, 0x3d, 0xd7, 0x41, 0xa4, 0x19, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x4, 0xa, 0x11, 0x19, 0x1f, 0x22, 0x24, 0x15, 0x25, 0x34, 0x3f, 0x46, 0x47, 0x48, 0x77, 0xef, 0xef, 0xa3, 0x31, 0x6b, 0xc2, 0x0, 0x0, 0x0, 0x60, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0xca, 0x85, 0xd, 0xc0, 0x40, 0x14, 0xc3, 0x50, 0x27, 0xf7, 0xd5, 0xfd, 0xd7, 0x2d, 0xa6, 0x4c, 0x16, 0x3f, 0xb9, 0xd0, 0x11, 0x90, 0xa3, 0x52, 0x77, 0x49, 0x8e, 0x86, 0xd2, 0x26, 0x16, 0x7b, 0x59, 0x32, 0x68, 0x3, 0x37, 0x5d, 0xe0, 0x59, 0x3b, 0x74, 0x31, 0x67, 0x4b, 0x3b, 0xf, 0x71, 0xe5, 0xe8, 0xf, 0xec, 0xc0, 0x1f, 0x28, 0xf8, 0x2, 0x14, 0xf9, 0x42, 0xa8, 0xfc, 0x21, 0x3b, 0xe4, 0x1, 0x6f, 0x0, 0x18, 0x11, 0xac, 0x99, 0xc0, 0xe, 0x25, 0x22, 0x2d, 0x76, 0xc6, 0x13, 0x1a, 0x8, 0xac, 0x78, 0xfc, 0x1c, 0x70, 0x30, 0x2b, 0xba, 0xe9, 0x31, 0x70, 0xc1, 0x7f, 0x3b, 0x77, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_menu_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x80, 0x81, 0x81, 0x11, 0x5d, 0xe0, 0xc1, 0x83, 0x7, 0xff, 0xf1, 0x69, 0x50, 0x50, 0x50, 0x40, 0xd1, 0xc3, 0x44, 0xa9, 0xb, 0xa8, 0x6f, 0x0, 0x23, 0x23, 0x63, 0x3c, 0x3, 0x3, 0xc3, 0x57, 0x2c, 0x6a, 0xbf, 0x33, 0x32, 0x32, 0xa6, 0x63, 0xa8, 0xc7, 0x66, 0xea, 0xfd, 0xfb, 0xf7, 0x35, 0x18, 0x18, 0x18, 0x56, 0x31, 0x32, 0x32, 0xea, 0x42, 0x85, 0x6e, 0x30, 0x33, 0x33, 0x87, 0xc9, 0xca, 0xca, 0x5e, 0x26, 0xca, 0x0, 0x6, 0x6, 0x6, 0x86, 0x17, 0x2f, 0x5e, 0x70, 0xff, 0xfc, 0xf9, 0x73, 0xa, 0x3, 0x3, 0x3, 0x3, 0x3b, 0x3b, 0x7b, 0x8e, 0x84, 0x84, 0x4, 0x36, 0x57, 0xd, 0x2, 0x0, 0x0, 0x67, 0xf2, 0x14, 0xc2, 0xc2, 0xbe, 0xf5, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tab_menu_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x6f, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x80, 0x81, 0x81, 0x11, 0x5d, 0xe0, 0xc1, 0x83, 0x7, 0xff, 0xf1, 0x69, 0x50, 0x50, 0x50, 0x40, 0xd1, 0xc3, 0x44, 0xa9, 0xb, 0xa8, 0x6f, 0x0, 0x23, 0x23, 0x63, 0x3c, 0x3, 0x3, 0xc3, 0x57, 0x2c, 0x6a, 0xbf, 0x33, 0x32, 0x32, 0xa6, 0x63, 0xa8, 0xc7, 0x66, 0xea, 0xfd, 0xfb, 0xf7, 0x35, 0x18, 0x18, 0x18, 0x56, 0x31, 0x32, 0x32, 0xea, 0x42, 0x85, 0x6e, 0x30, 0x33, 0x33, 0x87, 0xc9, 0xca, 0xca, 0x5e, 0x26, 0xca, 0x0, 0x6, 0x6, 0x6, 0x86, 0x17, 0x2f, 0x5e, 0x70, 0xff, 0xfc, 0xf9, 0x73, 0xa, 0x3, 0x3, 0x3, 0x3, 0x3b, 0x3b, 0x7b, 0x8e, 0x84, 0x84, 0x4, 0x36, 0x57, 0xd, 0x2, 0x0, 0x0, 0x67, 0xf2, 0x14, 0xc2, 0xc2, 0xbe, 0xf5, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x36, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x5, 0xa3, 0xe0, 0xc1, 0x7f, 0x54, 0x48, 0x3, 0x5, 0xf, 0xe3, 0x1e, 0x7c, 0x81, 0x4b, 0x7f, 0x7b, 0x98, 0x86, 0xc5, 0x15, 0xf7, 0x35, 0xee, 0x5f, 0x2, 0x4b, 0x5f, 0x7f, 0xac, 0x8b, 0xc3, 0xa1, 0x2f, 0xb8, 0x1f, 0xce, 0x7f, 0x38, 0xff, 0x5, 0x37, 0x75, 0xbd, 0xf, 0x0, 0x52, 0xd4, 0x48, 0xb8, 0x2d, 0x78, 0x5a, 0x91, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char toggle_off_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x7a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x2d, 0x26, 0x2c, 0x4d, 0x2b, 0x37, 0x63, 0x2f, 0x3f, 0x6e, 0x31, 0x43, 0x71, 0x32, 0x44, 0x6c, 0x31, 0x42, 0x51, 0x2c, 0x39, 0x47, 0x2a, 0x35, 0x66, 0x30, 0x40, 0x4d, 0x2b, 0x38, 0x32, 0x26, 0x2e, 0x26, 0x25, 0x2a, 0x2e, 0x25, 0x2c, 0x3c, 0x28, 0x31, 0x52, 0x2c, 0x39, 0x68, 0x30, 0x40, 0x27, 0x25, 0x2a, 0x50, 0x2c, 0x38, 0x5f, 0x2e, 0x3d, 0x35, 0x27, 0x2f, 0x38, 0x27, 0x30, 0x5e, 0x2e, 0x3d, 0x43, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x44, 0x2a, 0x34, 0x2b, 0x26, 0x2c, 0x64, 0x2f, 0x3f, 0x36, 0x27, 0x30, 0x37, 0x27, 0x30, 0x66, 0x2f, 0x40, 0x2c, 0x26, 0x2c, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x97, 0xb0, 0x86, 0xb4, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0x8, 0x17, 0x35, 0x86, 0xf3, 0x7, 0x3a, 0xb4, 0xb9, 0xb, 0x28, 0x8a, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xe6, 0x37, 0xf, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xe5, 0x7c, 0xf3, 0x66, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x6b, 0x52, 0x65, 0xa5, 0x98, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x2, 0x47, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x55, 0xfb, 0x5b, 0x93, 0x50, 0x18, 0x96, 0x3, 0xc, 0x48, 0x60, 0xde, 0x70, 0x9b, 0x43, 0x37, 0x75, 0xa6, 0x9b, 0xb5, 0xad, 0x56, 0x59, 0x99, 0xe9, 0xc6, 0x39, 0xb3, 0x56, 0x59, 0xcd, 0x4c, 0xbb, 0xd9, 0x3d, 0xdb, 0xd, 0x74, 0xa6, 0xa3, 0xdb, 0xff, 0x1e, 0x70, 0x68, 0x6e, 0xc0, 0xe0, 0xe9, 0xe9, 0x97, 0x7a, 0x79, 0x9e, 0x3, 0xf, 0x7c, 0xdf, 0xcb, 0x7b, 0xbe, 0xf3, 0x5d, 0x86, 0x86, 0xfe, 0x21, 0x10, 0x80, 0x24, 0xa9, 0x40, 0x90, 0x24, 0x20, 0x3c, 0xdd, 0x1, 0x45, 0x87, 0x18, 0x96, 0x3b, 0x17, 0x0, 0x8e, 0x65, 0x42, 0x34, 0x5, 0xdc, 0x7f, 0xa7, 0x86, 0x59, 0x5e, 0x10, 0xc3, 0x23, 0xa3, 0x63, 0xbe, 0x18, 0x1d, 0x9, 0x8b, 0x2, 0xcf, 0xe, 0x53, 0xe, 0x15, 0x60, 0x7c, 0x42, 0x9a, 0x8c, 0x44, 0x63, 0x53, 0xc5, 0x52, 0x0, 0x8a, 0x53, 0xb1, 0x68, 0x64, 0x52, 0x9a, 0x18, 0xef, 0x13, 0x1, 0xe2, 0xf2, 0xf4, 0x4c, 0x42, 0x81, 0x10, 0x21, 0x84, 0xed, 0x90, 0x9, 0x88, 0xca, 0xc8, 0x93, 0x24, 0x31, 0x33, 0x2d, 0xc7, 0x7b, 0x18, 0x88, 0x24, 0x37, 0x3b, 0xa7, 0xc0, 0xcd, 0x3b, 0x77, 0x2b, 0xf7, 0x30, 0xee, 0x3f, 0xd8, 0xb4, 0x58, 0xca, 0x70, 0x80, 0x8e, 0xb9, 0x59, 0x2e, 0x49, 0x9c, 0xed, 0x9f, 0x11, 0xe6, 0x15, 0xb4, 0xf5, 0xf0, 0xd1, 0xe3, 0xaa, 0xf5, 0xb9, 0xba, 0xfd, 0x64, 0xe7, 0xe9, 0xd6, 0xae, 0xa5, 0x64, 0xd0, 0x4e, 0xe6, 0x5, 0xa6, 0x1b, 0x7, 0x90, 0x5a, 0x38, 0xaf, 0xa0, 0xbd, 0x67, 0xcf, 0x7b, 0x2d, 0x5e, 0xbc, 0xdc, 0xdb, 0xf5, 0x8d, 0xc5, 0xe2, 0x42, 0xea, 0xf7, 0x26, 0x28, 0x59, 0x5c, 0x82, 0xaf, 0xf6, 0xb7, 0xfb, 0x2d, 0x5e, 0xef, 0xbf, 0xa9, 0xfa, 0x31, 0x2c, 0xa5, 0xe5, 0xc, 0x96, 0x40, 0xd0, 0xfc, 0x32, 0x7c, 0xfb, 0xee, 0xbd, 0xd3, 0xe2, 0xc3, 0xc7, 0x4f, 0xbe, 0xe7, 0xb1, 0xcc, 0xd3, 0x98, 0x0, 0x84, 0x84, 0xb, 0xf0, 0x60, 0xc7, 0x6d, 0xf1, 0xf9, 0xc0, 0x7e, 0xa8, 0xd5, 0x1b, 0xcd, 0x56, 0x49, 0x6d, 0x18, 0xb0, 0x16, 0xcd, 0x7a, 0x7b, 0x31, 0x9b, 0xc3, 0x7b, 0x20, 0x19, 0x31, 0x86, 0xe, 0x8f, 0xdc, 0x4, 0x47, 0x87, 0xf6, 0x43, 0xfb, 0xb8, 0xf6, 0xa5, 0x51, 0x53, 0x4d, 0x47, 0xd5, 0xf6, 0x36, 0x90, 0x4f, 0x33, 0x24, 0x26, 0x60, 0x2f, 0x5d, 0x46, 0x27, 0xa7, 0x6e, 0x82, 0xd3, 0x13, 0x5b, 0x80, 0xe9, 0x74, 0xdc, 0x51, 0x75, 0x93, 0x40, 0xef, 0x12, 0x14, 0xb, 0x2c, 0x85, 0x9, 0xe4, 0x2b, 0xa, 0xaa, 0x78, 0x4, 0xac, 0x5a, 0xc1, 0x77, 0x55, 0x37, 0x96, 0xaf, 0x75, 0xb5, 0xdd, 0x6e, 0x6b, 0xd6, 0x62, 0x7f, 0xbf, 0x2a, 0xdb, 0x4, 0x6c, 0x58, 0xf1, 0x55, 0xa0, 0x99, 0xa, 0xea, 0xdf, 0x54, 0xd3, 0x53, 0x6d, 0x7b, 0x28, 0x60, 0xc4, 0x6b, 0xd0, 0x37, 0x6, 0x7a, 0xa7, 0xa4, 0x35, 0x5b, 0x4e, 0x82, 0x6e, 0xc, 0x40, 0x28, 0x1b, 0x70, 0xa, 0x6a, 0x53, 0x6f, 0xd6, 0x4b, 0x4e, 0x82, 0xee, 0x29, 0x18, 0x79, 0xb0, 0x12, 0x90, 0x7, 0x5a, 0xe7, 0xbb, 0x11, 0xcb, 0x96, 0x66, 0x2f, 0x18, 0x2b, 0x92, 0x9d, 0x7, 0x66, 0x26, 0x5e, 0x47, 0x7f, 0x91, 0x89, 0x66, 0x2d, 0x2c, 0xfe, 0x79, 0x2d, 0xdc, 0x38, 0xab, 0x5, 0xef, 0x6a, 0xfc, 0xe1, 0xef, 0xdf, 0x5b, 0x8d, 0x66, 0x3f, 0xb8, 0xb9, 0xaa, 0xc0, 0x9f, 0xce, 0x7e, 0xe0, 0xe3, 0xbf, 0x7a, 0xab, 0xa7, 0x1f, 0x98, 0x1d, 0x89, 0x13, 0xd6, 0x6e, 0xc3, 0x32, 0xc4, 0xd, 0x9, 0xd9, 0x80, 0xc6, 0xe5, 0xe9, 0x9f, 0x58, 0x13, 0xb8, 0x78, 0x7f, 0x4f, 0x4b, 0x32, 0x92, 0x18, 0x89, 0xe6, 0x3, 0x5b, 0xa2, 0xf1, 0xf3, 0x7c, 0x34, 0x22, 0x4a, 0x4c, 0xd2, 0xd1, 0x98, 0x9, 0x2a, 0xc5, 0xf2, 0xd9, 0x74, 0x61, 0x7d, 0x2c, 0x0, 0xeb, 0x85, 0x74, 0x96, 0x67, 0x53, 0x94, 0x6b, 0x36, 0x10, 0x20, 0x43, 0xe7, 0x36, 0xe4, 0xe0, 0xb9, 0x20, 0x6f, 0xe4, 0xe8, 0x8c, 0xf7, 0x6c, 0x31, 0x26, 0x53, 0xf0, 0x60, 0x32, 0x46, 0xd3, 0x80, 0xc9, 0xf4, 0xff, 0xe2, 0x17, 0x82, 0xde, 0x40, 0xde, 0x2d, 0xc3, 0x2a, 0xca, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x7a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14, 0x14, 0x17, 0x20, 0x20, 0x25, 0x24, 0x24, 0x28, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0x13, 0x22, 0x22, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19, 0x19, 0x1c, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x12, 0x12, 0x14, 0x23, 0x23, 0x27, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x15, 0x15, 0x18, 0x20, 0x20, 0x25, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x24, 0x24, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x27, 0x15, 0x15, 0x18, 0x23, 0x23, 0x28, 0x12, 0x12, 0x14, 0x0, 0x0, 0x0, 0x1a, 0x1a, 0x1e, 0x0, 0x0, 0x0, 0x11, 0x11, 0x13, 0x22, 0x22, 0x26, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x24, 0x24, 0x29, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x28, 0x25, 0x25, 0x28, 0x25, 0x25, 0x29, 0x25, 0x25, 0x27, 0x2d, 0x26, 0x2c, 0x4d, 0x2b, 0x37, 0x63, 0x2f, 0x3f, 0x6e, 0x31, 0x43, 0x71, 0x32, 0x44, 0x6c, 0x31, 0x42, 0x51, 0x2c, 0x39, 0x47, 0x2a, 0x35, 0x66, 0x30, 0x40, 0x4d, 0x2b, 0x38, 0x32, 0x26, 0x2e, 0x26, 0x25, 0x2a, 0x2e, 0x25, 0x2c, 0x3c, 0x28, 0x31, 0x52, 0x2c, 0x39, 0x68, 0x30, 0x40, 0x27, 0x25, 0x2a, 0x50, 0x2c, 0x38, 0x5f, 0x2e, 0x3d, 0x35, 0x27, 0x2f, 0x38, 0x27, 0x30, 0x5e, 0x2e, 0x3d, 0x43, 0x2a, 0x34, 0x5f, 0x2f, 0x3e, 0x2f, 0x25, 0x2c, 0x44, 0x2a, 0x34, 0x2b, 0x26, 0x2c, 0x64, 0x2f, 0x3f, 0x36, 0x27, 0x30, 0x37, 0x27, 0x30, 0x66, 0x2f, 0x40, 0x2c, 0x26, 0x2c, 0x46, 0x2a, 0x35, 0x53, 0x2c, 0x39, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x32, 0x32, 0x37, 0x5d, 0x2e, 0x3d, 0x3e, 0x29, 0x32, 0xc9, 0xc9, 0xca, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x69, 0x30, 0x41, 0x2f, 0x26, 0x2d, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0x4e, 0x4e, 0x52, 0x48, 0x2b, 0x36, 0x2c, 0x26, 0x2b, 0x97, 0xb0, 0x86, 0xb4, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x98, 0xe5, 0xfa, 0xfe, 0x8, 0x17, 0x35, 0x86, 0xf3, 0x7, 0x3a, 0xb4, 0xb9, 0xb, 0x28, 0x8a, 0x8b, 0xf6, 0x45, 0x5, 0x9b, 0xe6, 0xe6, 0x37, 0xf, 0xfb, 0x4c, 0xfe, 0x4e, 0x4f, 0x50, 0xfb, 0x9c, 0xf6, 0x8c, 0x3b, 0xbb, 0x3c, 0x87, 0xf3, 0x53, 0x14, 0xe5, 0x7c, 0xf3, 0x66, 0x0, 0x0, 0x2, 0x29, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x3, 0x93, 0x24, 0x4b, 0x14, 0x85, 0x5f, 0xb9, 0xaa, 0x6d, 0x8e, 0x6d, 0xdb, 0x73, 0x2b, 0xb3, 0xe7, 0xad, 0x6d, 0xab, 0xdd, 0x63, 0xe3, 0xbf, 0x6f, 0x67, 0x65, 0xbb, 0xb4, 0xbb, 0x81, 0xc5, 0x97, 0x11, 0x27, 0x78, 0x4f, 0xea, 0xe2, 0xbf, 0x3f, 0x9, 0x86, 0xe5, 0x38, 0xde, 0x16, 0x8e, 0x63, 0x19, 0xc3, 0x70, 0x96, 0x17, 0x44, 0x49, 0x56, 0x1c, 0x36, 0x28, 0xb2, 0x24, 0xa, 0x3c, 0xab, 0xdf, 0x9d, 0x77, 0xca, 0x2e, 0xb7, 0xc7, 0xeb, 0xf3, 0x7, 0x2c, 0xf1, 0xfb, 0xbc, 0x1e, 0xb7, 0x4b, 0x76, 0xf2, 0x2d, 0xa7, 0x60, 0x83, 0xa1, 0x70, 0x24, 0x1a, 0x8b, 0x27, 0xb6, 0xc1, 0x86, 0xed, 0x44, 0x3c, 0x16, 0x8d, 0x84, 0x43, 0x41, 0xb6, 0x29, 0x3e, 0xd9, 0xd6, 0xde, 0xd1, 0xa9, 0x22, 0x84, 0x31, 0x6, 0xd, 0x4c, 0x40, 0x38, 0x85, 0xd, 0x4d, 0x3a, 0x3b, 0xda, 0xdb, 0x92, 0xd, 0xe, 0x4c, 0x97, 0xd2, 0xdd, 0xa3, 0xa2, 0x9d, 0xff, 0x6f, 0xdd, 0xbe, 0x43, 0xb9, 0x7b, 0x6f, 0x47, 0x73, 0x49, 0x21, 0x93, 0x73, 0xf4, 0x74, 0x2b, 0x5d, 0x4c, 0xfd, 0xfe, 0x92, 0xbb, 0x57, 0xc5, 0xf7, 0x1f, 0x3c, 0x7c, 0xf4, 0x18, 0x8, 0x8f, 0x9f, 0x3c, 0x7d, 0xf6, 0xfc, 0xfe, 0xb, 0xed, 0x24, 0x66, 0x37, 0xe9, 0x75, 0x4b, 0xb5, 0x77, 0x60, 0xfb, 0xfa, 0x7, 0x54, 0xfc, 0xf2, 0xd5, 0x6b, 0x68, 0xe0, 0xcd, 0xdb, 0x97, 0x2f, 0x2c, 0xdf, 0x62, 0xb0, 0xbf, 0xaf, 0x7a, 0x9, 0xbe, 0xcd, 0x33, 0x84, 0xde, 0xbd, 0x7f, 0x2, 0x4d, 0x7c, 0x78, 0xff, 0xf1, 0x31, 0x58, 0x30, 0x34, 0xdc, 0x36, 0x42, 0x8f, 0xc0, 0x8, 0xae, 0x51, 0xf4, 0xe9, 0xf3, 0x17, 0x68, 0xe1, 0xeb, 0xb7, 0x34, 0x58, 0x31, 0xea, 0x12, 0xa8, 0x1, 0x2b, 0xba, 0xc7, 0x50, 0xe6, 0x19, 0xe8, 0xc8, 0x66, 0x80, 0x92, 0xcb, 0x17, 0x8a, 0x25, 0xd8, 0x2d, 0x94, 0xd1, 0x64, 0xf, 0x8, 0xe3, 0x13, 0x93, 0xf4, 0xe, 0x9c, 0xe4, 0x89, 0xe3, 0xfd, 0x3, 0xd0, 0x71, 0xb0, 0xf, 0x94, 0xc3, 0xa3, 0xdc, 0x71, 0x21, 0xb7, 0x4b, 0x2, 0x35, 0xa1, 0x4c, 0xd, 0x4b, 0x1c, 0x35, 0x90, 0xa7, 0x67, 0xf0, 0xc9, 0x29, 0xe8, 0x38, 0x3d, 0xa9, 0x1c, 0x80, 0x4, 0x1d, 0x9d, 0xed, 0x9e, 0x13, 0x3, 0x22, 0x94, 0xed, 0x59, 0x99, 0xa7, 0x6, 0x6d, 0x73, 0x2a, 0xbe, 0x6d, 0xf0, 0x60, 0x8f, 0x6f, 0x13, 0x25, 0x41, 0x65, 0xb9, 0xc8, 0xef, 0x1e, 0x1e, 0x1e, 0xee, 0x69, 0x2, 0x94, 0xf9, 0xb6, 0x8a, 0x81, 0xec, 0x55, 0x2d, 0x4f, 0xb0, 0x47, 0x4e, 0x90, 0xbf, 0xdc, 0x25, 0x91, 0x44, 0x74, 0x27, 0x90, 0x3c, 0xb, 0xc8, 0xf2, 0xd, 0xce, 0xcf, 0x60, 0xaf, 0x58, 0xaa, 0x18, 0xe8, 0xdf, 0x80, 0x15, 0x27, 0x6c, 0x7e, 0x61, 0xb7, 0x78, 0x5e, 0xcc, 0x43, 0xab, 0x1, 0xfd, 0x5, 0x9a, 0x7, 0x8b, 0x36, 0x79, 0xb0, 0x77, 0x76, 0x5, 0x90, 0x2b, 0xed, 0x55, 0x84, 0xb2, 0x18, 0x16, 0x98, 0x5a, 0x26, 0x2e, 0xe1, 0x5f, 0xce, 0x44, 0x5a, 0xb, 0x83, 0x3f, 0x5f, 0xb, 0xcb, 0xb4, 0x16, 0xcc, 0xab, 0xf1, 0x9a, 0xc6, 0xdb, 0x57, 0x23, 0xed, 0x7, 0x2b, 0xab, 0x2a, 0xba, 0x69, 0xed, 0x7, 0xe6, 0x6c, 0xaf, 0xae, 0xd5, 0xfa, 0x1, 0xed, 0x48, 0x8a, 0x7b, 0x7d, 0x3, 0xa5, 0x10, 0x6d, 0x48, 0xb8, 0x2, 0x2a, 0x2f, 0x30, 0xa2, 0x73, 0xdd, 0xad, 0x24, 0x9b, 0x7b, 0x5a, 0x97, 0x14, 0xf6, 0x44, 0x63, 0x53, 0xdb, 0x60, 0xcb, 0xf6, 0x54, 0x2c, 0xea, 0x9, 0x4b, 0x5d, 0x6c, 0x6b, 0x57, 0xee, 0x93, 0x5d, 0x13, 0xc3, 0xb3, 0x9b, 0x1, 0x1b, 0x36, 0x67, 0x87, 0x27, 0x5c, 0x72, 0x1f, 0xcf, 0xe8, 0xa7, 0xca, 0x88, 0x30, 0xb9, 0xd5, 0x66, 0x3f, 0x17, 0xda, 0xb6, 0x26, 0x85, 0x11, 0x96, 0x31, 0x99, 0x4c, 0xfc, 0xf, 0x40, 0x27, 0xd3, 0xbf, 0xc4, 0x77, 0x82, 0xde, 0x40, 0xde, 0x4b, 0x3f, 0xe2, 0x98, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char toggle_on_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x1, 0x74, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x12, 0x12, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x1a, 0x1a, 0x1e, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x2c, 0x36, 0x27, 0x49, 0x65, 0x29, 0x5d, 0x85, 0x2a, 0x66, 0x95, 0x2a, 0x68, 0x99, 0x29, 0x64, 0x92, 0x28, 0x4c, 0x6b, 0x25, 0x27, 0x2d, 0x27, 0x43, 0x5c, 0x29, 0x5f, 0x89, 0x27, 0x49, 0x66, 0x25, 0x30, 0x3e, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x25, 0x2d, 0x38, 0x25, 0x3a, 0x4c, 0x27, 0x4d, 0x6b, 0x29, 0x60, 0x8c, 0x27, 0x44, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x59, 0x7f, 0x25, 0x34, 0x43, 0x25, 0x35, 0x45, 0x28, 0x58, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x40, 0x57, 0x27, 0x41, 0x57, 0x25, 0x2a, 0x33, 0x29, 0x5d, 0x87, 0x25, 0x34, 0x44, 0x25, 0x2b, 0x34, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x27, 0x43, 0x5b, 0x27, 0x4d, 0x6c, 0x27, 0x4e, 0x6d, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x28, 0x56, 0x7b, 0x26, 0x3b, 0x4e, 0x26, 0x3a, 0x4e, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0xe4, 0xe4, 0xe5, 0x27, 0x44, 0x5d, 0xdd, 0xc9, 0xf2, 0x7e, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0x8, 0x17, 0x35, 0x73, 0xd9, 0x7, 0x3a, 0x96, 0xf9, 0x9a, 0xb, 0x28, 0x76, 0xfb, 0x77, 0xde, 0x45, 0x5, 0x82, 0xc6, 0xc6, 0x37, 0xf, 0xe9, 0x4c, 0x4e, 0x4f, 0x50, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x37, 0x21, 0x5a, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x65, 0xb5, 0xdd, 0x88, 0x9f, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x2, 0x28, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0xd5, 0x55, 0x69, 0x57, 0xd3, 0x40, 0x14, 0x25, 0x93, 0xa4, 0x49, 0x24, 0x49, 0xd9, 0x42, 0xd7, 0x0, 0x85, 0x50, 0x2c, 0xb4, 0x68, 0x5b, 0xab, 0x28, 0xb2, 0xc, 0x4b, 0x95, 0x82, 0x56, 0xab, 0x42, 0x45, 0x5c, 0x9b, 0xad, 0x45, 0x11, 0x6d, 0x3, 0xa8, 0x7f, 0xde, 0xc4, 0x94, 0x26, 0x69, 0x30, 0x89, 0xc7, 0x2f, 0x7a, 0x3f, 0xe4, 0x9c, 0xcc, 0x3b, 0xef, 0xce, 0x7d, 0x6f, 0xde, 0x32, 0x30, 0xf0, 0xf, 0x1, 0x1, 0x28, 0x8a, 0xf9, 0x2, 0x45, 0x1, 0x72, 0xa5, 0x3b, 0xc0, 0xf0, 0x10, 0x41, 0x52, 0xd7, 0x7c, 0x40, 0x91, 0x44, 0x8, 0xc7, 0x80, 0xfb, 0x76, 0x6c, 0x90, 0xa4, 0x19, 0x36, 0x3c, 0x34, 0x3c, 0xe2, 0x89, 0xe1, 0xa1, 0x30, 0xcb, 0xd0, 0xe4, 0x20, 0xd6, 0xa7, 0x2, 0x8c, 0x8e, 0x71, 0xe3, 0x91, 0x68, 0x2c, 0x9e, 0x80, 0x3e, 0x48, 0xc4, 0x63, 0xd1, 0xc8, 0x38, 0x37, 0x36, 0xea, 0x10, 0x1, 0x92, 0xfc, 0xc4, 0xe4, 0xd4, 0x86, 0x9f, 0xf3, 0x25, 0x36, 0xa6, 0x26, 0x27, 0xf8, 0xa4, 0x8d, 0x1, 0x49, 0x51, 0xd3, 0x33, 0x82, 0xa7, 0xcf, 0xe6, 0xd6, 0x76, 0xf9, 0x81, 0x89, 0x87, 0x3b, 0x9b, 0x50, 0x98, 0x99, 0xa6, 0x52, 0x88, 0x15, 0x3f, 0xc1, 0xcc, 0x7a, 0x6a, 0xaf, 0xec, 0xee, 0x3d, 0x7a, 0x5c, 0x7d, 0x62, 0xe0, 0x69, 0xed, 0xd9, 0xf3, 0x17, 0xfb, 0x95, 0xc4, 0x2c, 0x43, 0xf4, 0xf2, 0x0, 0xd2, 0x73, 0xd7, 0x33, 0x9e, 0xfe, 0x7, 0xf5, 0x97, 0xf6, 0xff, 0xc3, 0x57, 0x7, 0x95, 0xcc, 0xfc, 0x5c, 0xfa, 0x32, 0x8, 0x8c, 0x67, 0x17, 0xbc, 0xfc, 0x8f, 0x5e, 0xd7, 0x6b, 0xce, 0x93, 0x5a, 0xfd, 0xcd, 0xd1, 0x42, 0x96, 0xcf, 0x99, 0x12, 0x10, 0x9c, 0x5e, 0xf4, 0x8c, 0xff, 0xed, 0xbb, 0xf7, 0xfd, 0x47, 0x87, 0x7b, 0x1f, 0xe0, 0x22, 0x8d, 0x9b, 0x4, 0x20, 0xc4, 0xdc, 0xb0, 0x4c, 0xd, 0x51, 0x92, 0x15, 0xa8, 0x4a, 0x4d, 0xa8, 0xb6, 0xba, 0x47, 0xc7, 0x1f, 0xdd, 0xa4, 0x9f, 0x8e, 0xe1, 0xcd, 0x7c, 0xc1, 0x8c, 0x1, 0x25, 0xd8, 0x98, 0x65, 0x69, 0x9d, 0x34, 0x3e, 0x4b, 0xd, 0x55, 0x6a, 0x59, 0x4, 0xa7, 0x5f, 0xdc, 0x4, 0x5f, 0x4f, 0x61, 0x31, 0x4b, 0xa0, 0x26, 0x1, 0x79, 0x2b, 0x6e, 0x9, 0x90, 0xda, 0x10, 0x9e, 0x74, 0x54, 0x4d, 0x56, 0x7b, 0x4, 0x67, 0xe7, 0x6e, 0x82, 0xf3, 0x33, 0x28, 0x94, 0x48, 0xcc, 0x24, 0xe0, 0x6f, 0x5b, 0x6f, 0xa8, 0x6a, 0xfa, 0xe7, 0x42, 0x54, 0x5b, 0x17, 0x5a, 0x8f, 0xa0, 0x5c, 0x75, 0x13, 0x54, 0xcb, 0x10, 0xde, 0xe1, 0xbb, 0x4, 0x64, 0xd8, 0x2a, 0xa2, 0xb6, 0xa1, 0x40, 0xfc, 0xa6, 0x3b, 0x7f, 0x17, 0x3, 0x2b, 0x20, 0xd8, 0xa2, 0x65, 0xd1, 0x3a, 0xb0, 0x2d, 0x2b, 0x3a, 0x81, 0x22, 0x5, 0xcd, 0x1, 0x8, 0xe5, 0x6d, 0xaf, 0xa0, 0xca, 0x9a, 0x2c, 0xfe, 0x4a, 0xa0, 0x16, 0xf4, 0x15, 0xf4, 0x3a, 0x58, 0xb2, 0x99, 0xda, 0x9d, 0xa6, 0x9e, 0x4b, 0x5, 0xc2, 0xa6, 0xe2, 0x5d, 0x7, 0x4b, 0x5c, 0xb7, 0xe, 0xfe, 0xba, 0x12, 0x8d, 0x5e, 0x98, 0xff, 0xf3, 0x5e, 0xb8, 0x6b, 0xf5, 0x42, 0x80, 0x6e, 0xdc, 0x77, 0x76, 0xe3, 0xf, 0x67, 0x37, 0x1a, 0xf3, 0xe0, 0xde, 0xb2, 0xa7, 0x86, 0xfe, 0x79, 0x90, 0x59, 0xbe, 0x6f, 0x9b, 0x7, 0xc6, 0x44, 0xa2, 0x98, 0x95, 0x55, 0x18, 0x18, 0xab, 0x2b, 0xc, 0x95, 0x74, 0xce, 0xb4, 0x14, 0xc1, 0xb1, 0x91, 0x68, 0x51, 0xf0, 0x77, 0x16, 0x8a, 0xd1, 0x8, 0xcb, 0x11, 0xa9, 0xbe, 0xc1, 0x8c, 0x60, 0x69, 0x92, 0xce, 0x67, 0x4b, 0x6b, 0x23, 0x3e, 0x58, 0x2b, 0x65, 0xf3, 0x34, 0x99, 0xc6, 0x5c, 0xbb, 0x1, 0x1, 0x39, 0xbc, 0xb0, 0xce, 0xfb, 0xef, 0x5, 0x7e, 0xbd, 0x80, 0xe7, 0xae, 0xde, 0x2d, 0xfa, 0x66, 0xf2, 0x5f, 0x4c, 0xfa, 0x6a, 0xfa, 0xcd, 0x66, 0xfa, 0x7f, 0xf1, 0x13, 0xb7, 0x71, 0x36, 0xc6, 0x87, 0x41, 0xd4, 0x5, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x20, 0x8, 0x3, 0x0, 0x0, 0x0, 0x95, 0x43, 0x8e, 0xb6, 0x0, 0x0, 0x1, 0x74, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xd, 0xd, 0xf, 0x1a, 0x1a, 0x1e, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x24, 0x24, 0x29, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa, 0xa, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11, 0x14, 0x23, 0x23, 0x28, 0x12, 0x12, 0x15, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0xb, 0xd, 0x23, 0x23, 0x28, 0xb, 0xb, 0xd, 0x1e, 0x1e, 0x22, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0x1a, 0x1a, 0x1e, 0x1a, 0x1a, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x20, 0x20, 0x24, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xe, 0x10, 0xb, 0xb, 0xd, 0x0, 0x0, 0x0, 0x13, 0x13, 0x15, 0x0, 0x0, 0x0, 0xb, 0xb, 0xc, 0x1d, 0x1d, 0x21, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x25, 0x25, 0x2a, 0x24, 0x24, 0x29, 0x25, 0x2c, 0x36, 0x27, 0x49, 0x65, 0x29, 0x5d, 0x85, 0x2a, 0x66, 0x95, 0x2a, 0x68, 0x99, 0x29, 0x64, 0x92, 0x28, 0x4c, 0x6b, 0x25, 0x27, 0x2d, 0x27, 0x43, 0x5c, 0x29, 0x5f, 0x89, 0x27, 0x49, 0x66, 0x25, 0x30, 0x3e, 0x25, 0x26, 0x2d, 0x25, 0x25, 0x2b, 0x25, 0x26, 0x2c, 0x25, 0x2d, 0x38, 0x25, 0x3a, 0x4c, 0x27, 0x4d, 0x6b, 0x29, 0x60, 0x8c, 0x27, 0x44, 0x5c, 0x27, 0x4b, 0x69, 0x28, 0x59, 0x7f, 0x25, 0x34, 0x43, 0x25, 0x35, 0x45, 0x28, 0x58, 0x7f, 0x25, 0x26, 0x2b, 0x27, 0x40, 0x57, 0x27, 0x41, 0x57, 0x25, 0x2a, 0x33, 0x29, 0x5d, 0x87, 0x25, 0x34, 0x44, 0x25, 0x2b, 0x34, 0x40, 0x40, 0x44, 0xad, 0xad, 0xaf, 0xff, 0xff, 0xff, 0xf2, 0xf2, 0xf2, 0x77, 0x77, 0x7a, 0x5b, 0x5b, 0x5f, 0x4e, 0x4e, 0x52, 0xc9, 0xc9, 0xca, 0x27, 0x43, 0x5b, 0x27, 0x4d, 0x6c, 0x27, 0x4e, 0x6d, 0xbb, 0xbb, 0xbd, 0x69, 0x69, 0x6c, 0x28, 0x56, 0x7b, 0x26, 0x3b, 0x4e, 0x26, 0x3a, 0x4e, 0x32, 0x32, 0x37, 0x84, 0x84, 0x87, 0xd6, 0xd6, 0xd7, 0x29, 0x61, 0x8d, 0x25, 0x2e, 0x39, 0x92, 0x92, 0x94, 0xa0, 0xa0, 0xa2, 0xe4, 0xe4, 0xe5, 0x27, 0x44, 0x5d, 0xdd, 0xc9, 0xf2, 0x7e, 0x0, 0x0, 0x0, 0x41, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1, 0x2, 0x3, 0x4, 0x9, 0xe, 0x13, 0x16, 0x18, 0x19, 0xa, 0x26, 0x36, 0x44, 0x4d, 0x52, 0x54, 0x55, 0x6, 0x12, 0x27, 0x43, 0x80, 0xc5, 0xe7, 0xf5, 0xfe, 0x8, 0x17, 0x35, 0x73, 0xd9, 0x7, 0x3a, 0x96, 0xf9, 0x9a, 0xb, 0x28, 0x76, 0xfb, 0x77, 0xde, 0x45, 0x5, 0x82, 0xc6, 0xc6, 0x37, 0xf, 0xe9, 0x4c, 0x4e, 0x4f, 0x50, 0x83, 0x78, 0x3b, 0x9c, 0x3c, 0x74, 0xda, 0x53, 0x14, 0x37, 0x21, 0x5a, 0x6c, 0x0, 0x0, 0x2, 0x4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xdd, 0x95, 0x63, 0x83, 0xdc, 0x60, 0x10, 0xc7, 0x1b, 0x3c, 0xc1, 0xda, 0x3e, 0xdb, 0x36, 0xe7, 0x6c, 0xdb, 0xa, 0xcf, 0xc6, 0x7e, 0xf8, 0x2a, 0x6d, 0xb8, 0xac, 0x7b, 0xbf, 0xf7, 0xf3, 0x1f, 0xcf, 0x7c, 0xf8, 0x97, 0xc0, 0x70, 0x82, 0x20, 0xb3, 0x42, 0x10, 0x38, 0x96, 0xd2, 0x1c, 0x27, 0x11, 0x45, 0x33, 0xac, 0x2d, 0xb, 0x2c, 0x43, 0x53, 0x88, 0xc4, 0xad, 0xde, 0x49, 0x3b, 0xe3, 0x70, 0xba, 0xdc, 0x1e, 0xaf, 0x2f, 0x23, 0x5e, 0x8f, 0xdb, 0xe5, 0x74, 0x30, 0x76, 0xd2, 0x14, 0x5, 0xee, 0xf, 0x4, 0x43, 0xe1, 0x48, 0x34, 0x16, 0x87, 0x2c, 0xc4, 0x63, 0xd1, 0x48, 0x38, 0x14, 0xc, 0xf8, 0x71, 0x83, 0x7d, 0xa2, 0xa0, 0xb0, 0xa8, 0x78, 0x4, 0x72, 0x64, 0xa4, 0xb8, 0xa8, 0xb0, 0x20, 0xa1, 0x53, 0xc0, 0x4a, 0xd8, 0xd2, 0xb2, 0x72, 0xc8, 0xc4, 0xe8, 0xd8, 0xf8, 0xc4, 0xa4, 0xc2, 0xd4, 0xf4, 0x28, 0x94, 0x97, 0x95, 0xb2, 0x25, 0x98, 0x96, 0x3f, 0xed, 0xac, 0xc8, 0x18, 0xfb, 0xcc, 0xec, 0xdc, 0xfc, 0xc2, 0xe2, 0xd2, 0x17, 0x96, 0x57, 0x56, 0xd7, 0xd6, 0x37, 0x66, 0xe2, 0x15, 0x4e, 0x5a, 0xad, 0x3, 0x5e, 0x59, 0x55, 0x5d, 0x93, 0xd1, 0x7e, 0x73, 0x6b, 0x1b, 0x74, 0xec, 0xec, 0x6e, 0xce, 0xd4, 0xd4, 0x56, 0x55, 0x7e, 0x4f, 0x82, 0x2c, 0x70, 0xd5, 0x41, 0x6, 0xf6, 0xf6, 0xb7, 0x56, 0xc0, 0xc0, 0xca, 0xd6, 0xc1, 0x5e, 0x5d, 0x7d, 0x41, 0x83, 0x12, 0x2, 0x86, 0x1c, 0x8d, 0x90, 0x89, 0xc3, 0xa3, 0x63, 0x30, 0xb1, 0x33, 0x77, 0x2, 0x8d, 0xe, 0xa4, 0x8, 0xe0, 0x94, 0xb3, 0x9, 0x54, 0x4e, 0xcf, 0x38, 0x5e, 0x0, 0x91, 0x93, 0x40, 0x94, 0x41, 0xe1, 0xfc, 0x2, 0x2c, 0x5c, 0x9e, 0x43, 0x73, 0x4b, 0xab, 0x92, 0x3, 0x41, 0xbb, 0xa2, 0xa0, 0x22, 0x5f, 0x9d, 0x5e, 0x73, 0xa7, 0x22, 0x27, 0x6b, 0x2, 0x37, 0xb7, 0x60, 0xe1, 0xee, 0x6, 0xda, 0xea, 0x69, 0x42, 0x11, 0x60, 0xda, 0x63, 0x5a, 0x0, 0xdc, 0x3d, 0xc0, 0xd5, 0x83, 0xf8, 0xc8, 0x8b, 0xaa, 0xc0, 0xd3, 0x33, 0x58, 0x78, 0x7e, 0x82, 0xf2, 0xe, 0x86, 0x54, 0x4, 0xa, 0x3a, 0xb5, 0x1e, 0x8a, 0x8f, 0x0, 0xf0, 0x72, 0x26, 0xca, 0x2f, 0x8f, 0xaa, 0xc0, 0xc4, 0x22, 0x58, 0x58, 0x9c, 0x0, 0xe8, 0x2a, 0xf8, 0x26, 0xc0, 0xb8, 0xb5, 0x21, 0xba, 0xff, 0x12, 0xc1, 0xd9, 0xeb, 0x67, 0xe3, 0xb7, 0xb3, 0x9c, 0x23, 0xa0, 0x5d, 0x6d, 0xa0, 0xf2, 0xf8, 0x0, 0xf7, 0xbc, 0xf0, 0x59, 0x40, 0xe0, 0x72, 0xad, 0x1, 0x4e, 0xb5, 0xe8, 0xba, 0x20, 0xf2, 0x8f, 0xfc, 0xd9, 0xd7, 0x2, 0x3e, 0xe6, 0xda, 0x5, 0xc, 0x39, 0xba, 0x41, 0xe3, 0xfe, 0x41, 0x2, 0x38, 0x15, 0x0, 0x24, 0x21, 0xf3, 0x1c, 0x74, 0x7, 0x11, 0xf6, 0xd3, 0x93, 0xa8, 0xee, 0x42, 0x6d, 0xfe, 0xbb, 0xd0, 0xa3, 0xed, 0x42, 0xe, 0xdb, 0xb8, 0x61, 0xdc, 0xc6, 0xa4, 0xba, 0x8d, 0xea, 0x3d, 0xe8, 0xed, 0xab, 0xc9, 0xe7, 0x1e, 0xd4, 0xf4, 0xf5, 0xab, 0xf7, 0x40, 0xb9, 0x48, 0xac, 0x73, 0x60, 0x10, 0x72, 0x66, 0x70, 0xc0, 0xc9, 0x26, 0x8c, 0x37, 0xad, 0x84, 0xe, 0xba, 0xc2, 0x91, 0xb6, 0x72, 0xc8, 0x4a, 0x79, 0x5b, 0x24, 0xec, 0xa, 0xd2, 0x25, 0xb8, 0xf9, 0x2a, 0x57, 0x32, 0x8e, 0x96, 0xfa, 0x8e, 0x21, 0x5f, 0x16, 0x86, 0x3a, 0xea, 0x5b, 0x1c, 0x4c, 0x25, 0x89, 0x59, 0xbf, 0x4a, 0x3, 0x6a, 0x1d, 0x2e, 0xc8, 0xfe, 0x17, 0xa, 0x86, 0x5b, 0x51, 0x3, 0x8e, 0xa5, 0xf9, 0x4c, 0x64, 0xe, 0x68, 0x9f, 0xe9, 0xbd, 0xf0, 0x9, 0xb7, 0x71, 0x36, 0xc6, 0x9b, 0x3d, 0x7f, 0x21, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tool_button_pressed_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x2, 0x1, 0x50, 0x4c, 0x54, 0x45, 0x29, 0x3a, 0x40, 0x2d, 0x3e, 0x44, 0x26, 0x34, 0x3b, 0x24, 0x34, 0x39, 0x23, 0x31, 0x38, 0x22, 0x31, 0x37, 0x22, 0x31, 0x37, 0x22, 0x30, 0x36, 0x22, 0x31, 0x36, 0x26, 0x34, 0x3c, 0x32, 0x44, 0x4c, 0x26, 0x34, 0x39, 0x23, 0x31, 0x36, 0x21, 0x2e, 0x34, 0x1f, 0x2c, 0x30, 0x1f, 0x2b, 0x2f, 0x1f, 0x2a, 0x2e, 0x1e, 0x2b, 0x2f, 0x1f, 0x2b, 0x2e, 0x36, 0x4b, 0x52, 0x25, 0x33, 0x38, 0x20, 0x2f, 0x32, 0x1c, 0x29, 0x2e, 0x1b, 0x26, 0x2a, 0x1a, 0x23, 0x26, 0x18, 0x22, 0x26, 0x19, 0x22, 0x26, 0x19, 0x23, 0x26, 0x19, 0x26, 0x29, 0x20, 0x2d, 0x32, 0x25, 0x31, 0x38, 0x3c, 0x51, 0x59, 0x23, 0x31, 0x37, 0x1f, 0x2b, 0x31, 0x1a, 0x25, 0x2b, 0x17, 0x20, 0x24, 0x15, 0x1c, 0x21, 0x14, 0x1b, 0x21, 0x14, 0x1c, 0x21, 0x13, 0x1b, 0x21, 0x15, 0x1d, 0x21, 0x1a, 0x25, 0x2a, 0x40, 0x57, 0x60, 0x23, 0x31, 0x36, 0x1f, 0x2b, 0x31, 0x1b, 0x25, 0x29, 0x16, 0x1e, 0x23, 0x14, 0x1b, 0x1d, 0x12, 0x19, 0x1d, 0x12, 0x1b, 0x1d, 0x14, 0x1a, 0x1d, 0x45, 0x5e, 0x67, 0x22, 0x32, 0x37, 0x20, 0x2d, 0x31, 0x1a, 0x26, 0x2a, 0x15, 0x1f, 0x25, 0x14, 0x1c, 0x1f, 0x12, 0x1b, 0x1f, 0x12, 0x1b, 0x20, 0x14, 0x1b, 0x1f, 0x15, 0x1e, 0x24, 0x1a, 0x25, 0x29, 0x4b, 0x64, 0x6d, 0x23, 0x32, 0x38, 0x20, 0x2e, 0x32, 0x1b, 0x27, 0x2b, 0x17, 0x22, 0x27, 0x16, 0x1e, 0x23, 0x14, 0x1e, 0x23, 0x16, 0x20, 0x24, 0x14, 0x1e, 0x22, 0x15, 0x1e, 0x22, 0x17, 0x21, 0x27, 0x1c, 0x27, 0x2c, 0x4f, 0x6a, 0x75, 0x21, 0x2f, 0x33, 0x1d, 0x29, 0x2d, 0x19, 0x23, 0x2a, 0x18, 0x22, 0x27, 0x16, 0x21, 0x27, 0x18, 0x23, 0x29, 0x17, 0x21, 0x26, 0x19, 0x23, 0x29, 0x1c, 0x28, 0x2d, 0x21, 0x2e, 0x33, 0x54, 0x70, 0x7c, 0x23, 0x33, 0x38, 0x22, 0x30, 0x34, 0x1e, 0x2a, 0x2f, 0x1a, 0x26, 0x2d, 0x1a, 0x25, 0x2b, 0x19, 0x25, 0x2b, 0x1a, 0x26, 0x2d, 0x1a, 0x26, 0x2c, 0x18, 0x25, 0x2a, 0x1a, 0x24, 0x2a, 0x1a, 0x25, 0x2c, 0x1d, 0x2a, 0x2f, 0x22, 0x2f, 0x34, 0x59, 0x77, 0x82, 0x23, 0x33, 0x39, 0x22, 0x30, 0x35, 0x1f, 0x2c, 0x31, 0x1c, 0x28, 0x30, 0x1c, 0x28, 0x2e, 0x1b, 0x29, 0x2f, 0x1c, 0x2a, 0x31, 0x1b, 0x28, 0x2f, 0x1c, 0x28, 0x2d, 0x1b, 0x27, 0x2f, 0x1f, 0x2b, 0x31, 0x5e, 0x7d, 0x8a, 0x24, 0x34, 0x39, 0x21, 0x2f, 0x37, 0x20, 0x2d, 0x34, 0x1d, 0x2b, 0x33, 0x1d, 0x2b, 0x32, 0x1d, 0x2d, 0x35, 0x1e, 0x2e, 0x36, 0x1f, 0x2e, 0x36, 0x1d, 0x2b, 0x34, 0x1d, 0x2b, 0x31, 0x1d, 0x2b, 0x32, 0x20, 0x2d, 0x32, 0x21, 0x2f, 0x36, 0x63, 0x83, 0x90, 0x25, 0x34, 0x39, 0x21, 0x31, 0x36, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x36, 0x20, 0x31, 0x39, 0x21, 0x33, 0x3b, 0x21, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1e, 0x2d, 0x33, 0x1f, 0x2d, 0x33, 0x21, 0x30, 0x36, 0x67, 0x8a, 0x97, 0x24, 0x33, 0x39, 0x20, 0x30, 0x36, 0x1f, 0x2f, 0x35, 0x21, 0x30, 0x37, 0x22, 0x32, 0x39, 0x21, 0x35, 0x3e, 0x24, 0x37, 0x41, 0x24, 0x36, 0x41, 0x21, 0x33, 0x3c, 0x21, 0x31, 0x38, 0x1e, 0x2f, 0x35, 0x1e, 0x2e, 0x35, 0x20, 0x2e, 0x35, 0x24, 0x31, 0x39, 0x6c, 0x90, 0x9e, 0x22, 0x30, 0x36, 0x1f, 0x2e, 0x36, 0x20, 0x30, 0x36, 0x20, 0x31, 0x39, 0x23, 0x34, 0x3d, 0x23, 0x37, 0x41, 0x26, 0x3c, 0x47, 0x26, 0x3b, 0x46, 0x22, 0x35, 0x3f, 0x22, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1f, 0x2d, 0x35, 0x21, 0x30, 0x36, 0x72, 0x96, 0xa5, 0x72, 0x96, 0xa5, 0xe8, 0x14, 0xaa, 0x3f, 0x0, 0x0, 0x0, 0xaa, 0x74, 0x52, 0x4e, 0x53, 0xc3, 0xc3, 0xe6, 0xd7, 0xcb, 0xc3, 0xbf, 0xbe, 0xbd, 0xe5, 0xc3, 0xd7, 0xc0, 0xac, 0xa0, 0x9a, 0x98, 0x98, 0x98, 0xc3, 0xcb, 0xac, 0x92, 0x82, 0x7b, 0x78, 0x78, 0x7b, 0x82, 0xac, 0xcb, 0xc3, 0xc3, 0xa0, 0x82, 0x6f, 0x67, 0x64, 0x63, 0x64, 0x67, 0x82, 0xc3, 0xbf, 0x9a, 0x7a, 0x67, 0x5e, 0x5b, 0x5a, 0x5e, 0xc3, 0xbd, 0x98, 0x78, 0x64, 0x5b, 0x57, 0x57, 0x5b, 0x64, 0x78, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x77, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0xbb, 0x96, 0x76, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x76, 0x96, 0xc3, 0xb5, 0x92, 0x75, 0x62, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x59, 0x62, 0x74, 0x92, 0xc3, 0xa9, 0x8b, 0x71, 0x61, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x61, 0x71, 0x8b, 0xa9, 0xc3, 0x95, 0x7e, 0x6b, 0x5e, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x5e, 0x6b, 0x7e, 0x95, 0xc3, 0x4f, 0x78, 0x99, 0x30, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xa9, 0x27, 0xf, 0x6, 0x4, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xff, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x40, 0x7, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x1c, 0x1c, 0x6c, 0xac, 0x2c, 0xcc, 0x9c, 0x8c, 0xc, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x2, 0x82, 0x82, 0x42, 0xfc, 0x7c, 0xbc, 0x3c, 0xdc, 0x5c, 0xc, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0x52, 0x92, 0xd2, 0x32, 0x62, 0xb2, 0x72, 0xc2, 0xc, 0xf2, 0xa, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0x6a, 0xea, 0x1a, 0xca, 0x9a, 0x8a, 0xa, 0xf2, 0xc, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x6, 0x86, 0x86, 0x6, 0x46, 0x7a, 0xba, 0x3a, 0xda, 0x5a, 0xc, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0x56, 0x96, 0xd6, 0x36, 0xb6, 0xa6, 0x26, 0xc6, 0xc, 0x76, 0xf6, 0xe, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0xe, 0x26, 0x76, 0xc, 0x5e, 0xf6, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x1, 0x1, 0xfe, 0x81, 0x41, 0xc1, 0x21, 0xf6, 0x5e, 0xc, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x9, 0x89, 0x49, 0x61, 0xa1, 0xc, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xa9, 0x29, 0xc9, 0xc, 0xf9, 0x5, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0x5, 0xf9, 0xc, 0xb5, 0x75, 0xf5, 0xd, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0x75, 0xb5, 0xc, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x13, 0x26, 0x4e, 0x9a, 0x3c, 0x65, 0xea, 0xb4, 0xe9, 0x33, 0x66, 0x76, 0x33, 0xcc, 0x9a, 0x3d, 0x67, 0xee, 0xbc, 0xf9, 0xb, 0x16, 0x2e, 0x5a, 0xbc, 0x64, 0xe9, 0xb2, 0xe5, 0x2b, 0x66, 0x31, 0xac, 0x44, 0x3, 0x0, 0xa4, 0xd7, 0x4d, 0x73, 0x12, 0x21, 0x19, 0xde, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x1, 0xfe, 0x50, 0x4c, 0x54, 0x45, 0x29, 0x3a, 0x40, 0x2d, 0x3e, 0x44, 0x26, 0x34, 0x3b, 0x24, 0x34, 0x39, 0x23, 0x31, 0x38, 0x22, 0x31, 0x37, 0x22, 0x31, 0x37, 0x22, 0x30, 0x36, 0x22, 0x31, 0x36, 0x26, 0x34, 0x3c, 0x32, 0x44, 0x4c, 0x26, 0x34, 0x39, 0x23, 0x31, 0x36, 0x21, 0x2e, 0x34, 0x1f, 0x2c, 0x30, 0x1f, 0x2b, 0x2f, 0x1f, 0x2a, 0x2e, 0x1e, 0x2b, 0x2f, 0x1f, 0x2b, 0x2e, 0x36, 0x4b, 0x52, 0x25, 0x33, 0x38, 0x20, 0x2f, 0x32, 0x1c, 0x29, 0x2e, 0x1b, 0x26, 0x2a, 0x1a, 0x23, 0x26, 0x18, 0x22, 0x26, 0x19, 0x22, 0x26, 0x19, 0x23, 0x26, 0x19, 0x26, 0x29, 0x20, 0x2d, 0x32, 0x25, 0x31, 0x38, 0x3c, 0x51, 0x59, 0x23, 0x31, 0x37, 0x1f, 0x2b, 0x31, 0x1a, 0x25, 0x2b, 0x17, 0x20, 0x24, 0x15, 0x1c, 0x21, 0x14, 0x1b, 0x21, 0x14, 0x1c, 0x21, 0x13, 0x1b, 0x21, 0x15, 0x1d, 0x21, 0x1a, 0x25, 0x2a, 0x40, 0x57, 0x60, 0x23, 0x31, 0x36, 0x1f, 0x2b, 0x31, 0x1b, 0x25, 0x29, 0x16, 0x1e, 0x23, 0x14, 0x1b, 0x1d, 0x12, 0x19, 0x1d, 0x12, 0x1b, 0x1d, 0x14, 0x1a, 0x1d, 0x45, 0x5e, 0x67, 0x22, 0x32, 0x37, 0x20, 0x2d, 0x31, 0x1a, 0x26, 0x2a, 0x15, 0x1f, 0x25, 0x14, 0x1c, 0x1f, 0x12, 0x1b, 0x1f, 0x12, 0x1b, 0x20, 0x14, 0x1b, 0x1f, 0x15, 0x1e, 0x24, 0x1a, 0x25, 0x29, 0x4b, 0x64, 0x6d, 0x23, 0x32, 0x38, 0x20, 0x2e, 0x32, 0x1b, 0x27, 0x2b, 0x17, 0x22, 0x27, 0x16, 0x1e, 0x23, 0x14, 0x1e, 0x23, 0x16, 0x20, 0x24, 0x14, 0x1e, 0x22, 0x15, 0x1e, 0x22, 0x17, 0x21, 0x27, 0x1c, 0x27, 0x2c, 0x4f, 0x6a, 0x75, 0x21, 0x2f, 0x33, 0x1d, 0x29, 0x2d, 0x19, 0x23, 0x2a, 0x18, 0x22, 0x27, 0x16, 0x21, 0x27, 0x18, 0x23, 0x29, 0x17, 0x21, 0x26, 0x19, 0x23, 0x29, 0x1c, 0x28, 0x2d, 0x21, 0x2e, 0x33, 0x54, 0x70, 0x7c, 0x23, 0x33, 0x38, 0x22, 0x30, 0x34, 0x1e, 0x2a, 0x2f, 0x1a, 0x26, 0x2d, 0x1a, 0x25, 0x2b, 0x19, 0x25, 0x2b, 0x1a, 0x26, 0x2d, 0x1a, 0x26, 0x2c, 0x18, 0x25, 0x2a, 0x1a, 0x24, 0x2a, 0x1a, 0x25, 0x2c, 0x1d, 0x2a, 0x2f, 0x22, 0x2f, 0x34, 0x59, 0x77, 0x82, 0x23, 0x33, 0x39, 0x22, 0x30, 0x35, 0x1f, 0x2c, 0x31, 0x1c, 0x28, 0x30, 0x1c, 0x28, 0x2e, 0x1b, 0x29, 0x2f, 0x1c, 0x2a, 0x31, 0x1b, 0x28, 0x2f, 0x1c, 0x28, 0x2d, 0x1b, 0x27, 0x2f, 0x1f, 0x2b, 0x31, 0x5e, 0x7d, 0x8a, 0x24, 0x34, 0x39, 0x21, 0x2f, 0x37, 0x20, 0x2d, 0x34, 0x1d, 0x2b, 0x33, 0x1d, 0x2b, 0x32, 0x1d, 0x2d, 0x35, 0x1e, 0x2e, 0x36, 0x1f, 0x2e, 0x36, 0x1d, 0x2b, 0x34, 0x1d, 0x2b, 0x31, 0x1d, 0x2b, 0x32, 0x20, 0x2d, 0x32, 0x21, 0x2f, 0x36, 0x63, 0x83, 0x90, 0x25, 0x34, 0x39, 0x21, 0x31, 0x36, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x34, 0x1f, 0x2e, 0x36, 0x20, 0x31, 0x39, 0x21, 0x33, 0x3b, 0x21, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1e, 0x2d, 0x33, 0x1f, 0x2d, 0x33, 0x21, 0x30, 0x36, 0x67, 0x8a, 0x97, 0x24, 0x33, 0x39, 0x20, 0x30, 0x36, 0x1f, 0x2f, 0x35, 0x21, 0x30, 0x37, 0x22, 0x32, 0x39, 0x21, 0x35, 0x3e, 0x24, 0x37, 0x41, 0x24, 0x36, 0x41, 0x21, 0x33, 0x3c, 0x21, 0x31, 0x38, 0x1e, 0x2f, 0x35, 0x1e, 0x2e, 0x35, 0x20, 0x2e, 0x35, 0x24, 0x31, 0x39, 0x6c, 0x90, 0x9e, 0x22, 0x30, 0x36, 0x1f, 0x2e, 0x36, 0x20, 0x30, 0x36, 0x20, 0x31, 0x39, 0x23, 0x34, 0x3d, 0x23, 0x37, 0x41, 0x26, 0x3c, 0x47, 0x26, 0x3b, 0x46, 0x22, 0x35, 0x3f, 0x22, 0x32, 0x3b, 0x1f, 0x30, 0x37, 0x1f, 0x2e, 0x35, 0x1f, 0x2d, 0x35, 0x21, 0x30, 0x36, 0x72, 0x96, 0xa5, 0x7e, 0x8c, 0xc3, 0xb0, 0x0, 0x0, 0x0, 0xaa, 0x74, 0x52, 0x4e, 0x53, 0xc3, 0xc3, 0xe6, 0xd7, 0xcb, 0xc3, 0xbf, 0xbe, 0xbd, 0xe5, 0xc3, 0xd7, 0xc0, 0xac, 0xa0, 0x9a, 0x98, 0x98, 0x98, 0xc3, 0xcb, 0xac, 0x92, 0x82, 0x7b, 0x78, 0x78, 0x7b, 0x82, 0xac, 0xcb, 0xc3, 0xc3, 0xa0, 0x82, 0x6f, 0x67, 0x64, 0x63, 0x64, 0x67, 0x82, 0xc3, 0xbf, 0x9a, 0x7a, 0x67, 0x5e, 0x5b, 0x5a, 0x5e, 0xc3, 0xbd, 0x98, 0x78, 0x64, 0x5b, 0x57, 0x57, 0x5b, 0x64, 0x78, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x78, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x77, 0x98, 0xc3, 0xbd, 0x98, 0x77, 0x63, 0x5a, 0x57, 0x56, 0x57, 0x5a, 0x63, 0x77, 0xc3, 0xbb, 0x96, 0x76, 0x63, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x5a, 0x63, 0x76, 0x96, 0xc3, 0xb5, 0x92, 0x75, 0x62, 0x5a, 0x57, 0x56, 0x56, 0x57, 0x59, 0x62, 0x74, 0x92, 0xc3, 0xa9, 0x8b, 0x71, 0x61, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x61, 0x71, 0x8b, 0xa9, 0xc3, 0x95, 0x7e, 0x6b, 0x5e, 0x59, 0x57, 0x56, 0x56, 0x57, 0x59, 0x5e, 0x6b, 0x7e, 0x95, 0xc3, 0x4f, 0x78, 0x99, 0x30, 0x0, 0x0, 0x0, 0x67, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5c, 0x8b, 0x5, 0x2, 0xc3, 0x30, 0xc, 0xc4, 0x72, 0x5d, 0x39, 0xf4, 0xff, 0x67, 0x8e, 0x79, 0x1a, 0x37, 0xa0, 0xa0, 0x6d, 0x5d, 0x6b, 0x2a, 0x5a, 0xfd, 0x30, 0xe6, 0x1, 0xf4, 0xa7, 0x76, 0xfa, 0x37, 0x74, 0x7, 0x98, 0x52, 0x83, 0x46, 0x97, 0x41, 0xfb, 0xd6, 0x2d, 0x86, 0xae, 0xfe, 0x84, 0x6b, 0x6d, 0x32, 0x6e, 0x58, 0x28, 0x22, 0x3a, 0x41, 0x32, 0xde, 0xd7, 0x6a, 0x67, 0x5b, 0xb7, 0xb7, 0xc9, 0xb0, 0xd8, 0xd6, 0x3a, 0x65, 0x34, 0xb4, 0x21, 0x8f, 0x1c, 0x3, 0x6d, 0x21, 0x84, 0x5d, 0x32, 0x8a, 0x48, 0x22, 0x6e, 0xda, 0xa8, 0x92, 0x36, 0x3e, 0x87, 0xea, 0x7b, 0x7e, 0x0, 0x62, 0xa8, 0x25, 0xad, 0x68, 0x1d, 0x7d, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tooltip_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0xdd, 0xdd, 0xdd, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0xdd, 0xdd, 0xdd, 0xfe, 0x3f, 0x83, 0xa9, 0x0, 0x0, 0x0, 0xd, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xcc, 0xff, 0xb7, 0x4a, 0xbe, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xc, 0x81, 0xb3, 0x51, 0x63, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x44, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xc5, 0xcf, 0xbb, 0x15, 0x0, 0x20, 0x8, 0x43, 0xd1, 0x80, 0x28, 0xf8, 0x41, 0xf7, 0xdf, 0xd6, 0x86, 0x63, 0xa1, 0x3, 0x78, 0xcb, 0x54, 0x79, 0x0, 0x71, 0x92, 0x90, 0x98, 0x0, 0xca, 0x45, 0x2d, 0x68, 0xc9, 0x4, 0xae, 0xad, 0x7b, 0xe8, 0xad, 0x32, 0x44, 0xe7, 0x1a, 0x61, 0x4d, 0x15, 0x88, 0xf9, 0x38, 0xdc, 0xfe, 0xd, 0xf7, 0xb1, 0xe7, 0xfa, 0x13, 0x77, 0xe7, 0x6f, 0xdc, 0x6c, 0x9, 0x25, 0x82, 0x67, 0x68, 0x78, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x30, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2d, 0x2c, 0x2f, 0x48, 0x46, 0x4a, 0xdd, 0xdd, 0xdd, 0x4c, 0x4a, 0x4e, 0x48, 0x46, 0x4a, 0x40, 0x3e, 0x42, 0xbc, 0x3, 0x4f, 0xe9, 0x0, 0x0, 0x0, 0xd, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0xf5, 0xfe, 0xcc, 0xff, 0xb7, 0x4a, 0xbe, 0x0, 0x0, 0x0, 0x38, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x54, 0x76, 0x1, 0x2, 0x23, 0x1, 0x6, 0xd1, 0xf4, 0xe, 0x20, 0x28, 0xb, 0x64, 0xd0, 0x5c, 0x7d, 0x17, 0x8, 0x76, 0x4d, 0x62, 0x70, 0x7f, 0x7f, 0x6, 0x8, 0xfe, 0x95, 0x30, 0x78, 0xdc, 0x1, 0x31, 0xce, 0xb6, 0x50, 0xc8, 0x80, 0x1b, 0x8, 0xb7, 0x2, 0x6e, 0x29, 0xdc, 0x19, 0x0, 0xcf, 0x24, 0x4d, 0xb3, 0xd0, 0x4d, 0xb9, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0xd, 0xf6, 0xb4, 0x61, 0xf5, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x4, 0x3, 0x0, 0x0, 0x0, 0x7f, 0x1c, 0xd2, 0x8e, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x17, 0x16, 0x1a, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x21, 0x1f, 0x25, 0x1d, 0x1c, 0x21, 0x20, 0x1e, 0x24, 0x1d, 0x1c, 0x21, 0x1d, 0x1c, 0x21, 0x24, 0x22, 0x29, 0x28, 0x26, 0x2d, 0x28, 0x26, 0x2e, 0x2b, 0x2a, 0x31, 0x2c, 0x2a, 0x32, 0xff, 0xff, 0xff, 0xb9, 0x11, 0x56, 0x3e, 0x0, 0x0, 0x0, 0x8, 0x74, 0x52, 0x4e, 0x53, 0x6f, 0xef, 0xf7, 0xf7, 0xf0, 0xf9, 0xf1, 0xee, 0xcf, 0x21, 0xd2, 0xdf, 0x0, 0x0, 0x0, 0x2d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x54, 0x36, 0x36, 0x12, 0x60, 0xf0, 0x98, 0xb5, 0x6a, 0x65, 0xb, 0x43, 0xe4, 0x9e, 0x33, 0xa7, 0xa7, 0x32, 0x58, 0x9d, 0x39, 0x73, 0x66, 0x31, 0x16, 0x12, 0x22, 0xb, 0x52, 0xd9, 0xc6, 0xc0, 0x2, 0xd4, 0x55, 0x0, 0x0, 0xc, 0x14, 0x1a, 0x90, 0x55, 0x1a, 0xec, 0xdb, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_bg_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x95, 0xce, 0x31, 0x12, 0x2, 0x21, 0x10, 0x44, 0xd1, 0x3f, 0x40, 0xa1, 0x44, 0xa6, 0x46, 0xde, 0x63, 0x4f, 0xe5, 0x15, 0x38, 0xb2, 0xd6, 0x6, 0xb0, 0xc8, 0x30, 0x6, 0x96, 0xac, 0x56, 0x99, 0xf8, 0xb3, 0x7e, 0x51, 0xcb, 0xf9, 0x1a, 0xb3, 0x3f, 0xa, 0xaf, 0xc, 0xad, 0x2d, 0xcb, 0xe5, 0x76, 0x38, 0x5, 0x76, 0xec, 0x6c, 0xf7, 0xe0, 0x53, 0xe0, 0x13, 0xa1, 0x27, 0x27, 0x43, 0x26, 0x81, 0x20, 0xc8, 0x70, 0xfc, 0xe8, 0xf, 0x34, 0x67, 0xd8, 0x9c, 0x86, 0x61, 0x2e, 0x68, 0xe9, 0x91, 0xaf, 0x4b, 0x5a, 0x7d, 0x2a, 0x2c, 0x3, 0xed, 0xef, 0x1e, 0x6b, 0xcb, 0x4f, 0xa6, 0x66, 0x2b, 0x25, 0x6, 0x1, 0x37, 0x40, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xa, 0x0, 0x0, 0x0, 0xa, 0x8, 0x4, 0x0, 0x0, 0x0, 0x27, 0x3b, 0x7, 0x36, 0x0, 0x0, 0x0, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x94, 0xc8, 0x67, 0x6b, 0x60, 0xe6, 0x60, 0x64, 0x80, 0x80, 0xff, 0xc, 0x7f, 0x7f, 0xfc, 0x6a, 0x60, 0x94, 0xfb, 0xc0, 0xce, 0xcf, 0xc2, 0x80, 0x10, 0xfc, 0xc3, 0xf0, 0xf3, 0x23, 0xa3, 0xe2, 0x4f, 0xe, 0x36, 0x54, 0xc1, 0x1f, 0xbf, 0x18, 0x95, 0xbe, 0x73, 0x70, 0xb0, 0x30, 0xc0, 0x1, 0x48, 0xf0, 0x7, 0x85, 0x82, 0x58, 0x2d, 0xc2, 0xe6, 0xa4, 0x4f, 0x20, 0xc7, 0x37, 0x32, 0xb3, 0x23, 0x39, 0xfe, 0xfb, 0xaf, 0x46, 0x0, 0xee, 0x2a, 0x2f, 0xce, 0x4c, 0x47, 0x66, 0xf6, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_bg_focus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x73, 0x7a, 0x7a, 0xf4, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xdb, 0xb, 0x4, 0x12, 0x2d, 0x3a, 0xb5, 0x1b, 0x14, 0x49, 0x0, 0x0, 0x2, 0xd9, 0x49, 0x44, 0x41, 0x54, 0x58, 0xc3, 0xc5, 0x57, 0x31, 0x8e, 0x14, 0x31, 0x10, 0xac, 0xea, 0x3d, 0x11, 0x91, 0xdf, 0x49, 0xf7, 0xf, 0x78, 0x1, 0xf, 0x40, 0x84, 0x44, 0x10, 0xf2, 0x20, 0x42, 0x62, 0x12, 0xc4, 0x3, 0x78, 0x1, 0xff, 0x21, 0x42, 0xb8, 0x8a, 0xc0, 0x1e, 0x4f, 0xdb, 0xe3, 0xb9, 0xbb, 0x45, 0x20, 0x7c, 0x1a, 0xdd, 0x8c, 0xec, 0xed, 0xae, 0xae, 0xea, 0xee, 0xe9, 0xe1, 0xfd, 0xed, 0xdd, 0xb, 0x0, 0xdf, 0xf1, 0x7f, 0xd6, 0x4b, 0xde, 0xdf, 0xde, 0xf9, 0xcb, 0xeb, 0x9f, 0xff, 0xc5, 0xfb, 0x9b, 0xaf, 0xcf, 0x70, 0xb3, 0x3d, 0x3c, 0xff, 0xf0, 0xd, 0x24, 0x11, 0x71, 0x1, 0x49, 0x90, 0x4, 0x0, 0x4, 0xd3, 0x2f, 0xb6, 0x7b, 0xf, 0xff, 0x86, 0x2d, 0x8c, 0x47, 0x60, 0x1b, 0x0, 0x61, 0x1b, 0xb6, 0x21, 0x15, 0xd8, 0xc6, 0x8f, 0x8f, 0xaf, 0x0, 0x60, 0x7, 0x0, 0xa2, 0x2, 0x20, 0x11, 0x41, 0x30, 0xa2, 0x2, 0xc1, 0xb5, 0x0, 0x8c, 0x79, 0xd9, 0x80, 0x24, 0x48, 0x0, 0x48, 0x28, 0x9d, 0xb9, 0xd9, 0xd, 0xb0, 0x31, 0x40, 0x5c, 0x2e, 0x1, 0x46, 0x0, 0xd, 0xd0, 0xb6, 0xef, 0x35, 0x8e, 0x13, 0x6, 0xbc, 0x33, 0x60, 0xa3, 0x9a, 0x11, 0x6c, 0x82, 0xe6, 0xa, 0x0, 0x86, 0xe8, 0x2f, 0x71, 0xa9, 0xf7, 0x9c, 0x4d, 0x1f, 0x69, 0x5e, 0x1, 0xd8, 0xa3, 0x37, 0xa4, 0xa, 0x27, 0x1a, 0x13, 0x79, 0x25, 0x9, 0xaa, 0xe3, 0xd8, 0x9c, 0x5f, 0xea, 0x7d, 0x67, 0x80, 0xd7, 0x31, 0x20, 0xab, 0x3, 0x20, 0x5, 0x20, 0x2a, 0x13, 0x41, 0x40, 0x2b, 0x0, 0x76, 0x22, 0xb9, 0xb1, 0xd1, 0x92, 0x91, 0x5d, 0x86, 0xf3, 0x35, 0xef, 0x5, 0xa3, 0x25, 0x60, 0xd, 0x6e, 0x66, 0xe5, 0x0, 0xc0, 0xa8, 0x54, 0x1, 0x6, 0xe9, 0x16, 0x9f, 0x4f, 0xdc, 0x1c, 0x13, 0xed, 0xb1, 0x55, 0x31, 0x78, 0x70, 0x8e, 0xca, 0xcb, 0x8e, 0x6a, 0xbe, 0x56, 0x88, 0x67, 0x38, 0xdb, 0x75, 0x58, 0x76, 0xdf, 0x1b, 0x6c, 0x7a, 0xc, 0x6c, 0x90, 0x0, 0xfd, 0xe0, 0xe8, 0x98, 0xe4, 0x4, 0xe2, 0x69, 0xc, 0xe4, 0x40, 0xaa, 0xf9, 0x63, 0x70, 0xbb, 0x4, 0x16, 0x9c, 0x12, 0xa7, 0x3e, 0xe7, 0x38, 0xb3, 0x4, 0x2b, 0x6f, 0xc7, 0x23, 0xbb, 0xc3, 0x66, 0xdb, 0x38, 0x7, 0x0, 0xcf, 0x32, 0x34, 0xb6, 0x52, 0xb4, 0x3c, 0xf7, 0x35, 0x10, 0xd9, 0xf7, 0x6, 0x56, 0x93, 0x4, 0x4b, 0x0, 0x43, 0x28, 0xf9, 0x4a, 0x3d, 0x6e, 0xb0, 0x3e, 0x9, 0x31, 0xa9, 0x62, 0xd6, 0xc4, 0x36, 0x9c, 0xf2, 0xd9, 0xbd, 0x41, 0x2d, 0x24, 0x68, 0xc7, 0x1f, 0x62, 0x60, 0x6a, 0xc1, 0x7f, 0x95, 0x81, 0xaa, 0x13, 0x61, 0x9, 0xa6, 0xf6, 0x1c, 0x30, 0x17, 0x11, 0x6f, 0x48, 0x12, 0x3b, 0xf3, 0x7b, 0xc2, 0xeb, 0xca, 0x92, 0xb7, 0x72, 0x5f, 0x31, 0x90, 0x11, 0x4e, 0x48, 0xb3, 0x13, 0xa6, 0xcc, 0x3e, 0x51, 0x60, 0x91, 0x53, 0x55, 0x87, 0xf3, 0x2a, 0x98, 0xff, 0x7c, 0x6c, 0x1a, 0xf9, 0xec, 0xda, 0xeb, 0x94, 0x13, 0x43, 0xdd, 0x3f, 0x2a, 0x41, 0xd2, 0xb, 0x27, 0x65, 0xe8, 0x13, 0x20, 0x29, 0x3f, 0xc6, 0x7c, 0x48, 0x65, 0x8, 0x41, 0xda, 0xa4, 0xd5, 0x11, 0xc0, 0x2a, 0x61, 0xce, 0x18, 0x58, 0xd2, 0xbe, 0x98, 0x48, 0x96, 0xdd, 0xf5, 0xbc, 0x11, 0x65, 0xb6, 0x12, 0x55, 0xcb, 0xde, 0xb3, 0x78, 0x27, 0x78, 0xdc, 0xcb, 0x72, 0xe6, 0xd7, 0x8a, 0x27, 0xe6, 0x52, 0x1f, 0x10, 0xe0, 0xb8, 0x92, 0x81, 0xb4, 0x3f, 0x1, 0x1d, 0xed, 0x6c, 0xd4, 0xef, 0x12, 0x2f, 0x73, 0xa0, 0xe, 0xf, 0x42, 0x24, 0x20, 0xf, 0x91, 0xbf, 0x6e, 0x44, 0xfb, 0xde, 0xa1, 0x4, 0xa5, 0x7, 0xaa, 0xa0, 0x23, 0xad, 0xd4, 0x4b, 0xaa, 0x73, 0x0, 0xb7, 0xa1, 0x82, 0x87, 0x46, 0x74, 0x9a, 0xf, 0x48, 0x5d, 0xb3, 0xd, 0xa2, 0xb0, 0x96, 0xe5, 0x7d, 0xc8, 0x81, 0x19, 0xf1, 0x36, 0x2b, 0xba, 0xbd, 0x5e, 0xb3, 0xb7, 0x55, 0x12, 0x76, 0x90, 0xc4, 0x3a, 0x1, 0xa7, 0x66, 0xbc, 0x3, 0x90, 0xe0, 0x8, 0xc8, 0x42, 0x29, 0xa5, 0x7b, 0xa2, 0x63, 0x9f, 0x88, 0x26, 0xa, 0x9c, 0x85, 0x6f, 0x7b, 0x2b, 0x0, 0x92, 0x51, 0x4a, 0x81, 0x5c, 0x2a, 0xcb, 0x2a, 0x47, 0x0, 0xb0, 0x2b, 0x8, 0x11, 0x62, 0x20, 0x58, 0x20, 0x47, 0x77, 0x5a, 0xe5, 0x98, 0x43, 0x3f, 0x2, 0xd8, 0xc1, 0xa5, 0x39, 0x40, 0x82, 0xb5, 0xd9, 0xd7, 0x5a, 0x2, 0x59, 0x80, 0x9, 0x8a, 0x0, 0x7f, 0x1, 0x8, 0x44, 0x8, 0x64, 0xe0, 0xe8, 0x6e, 0x4b, 0xb4, 0x87, 0xa6, 0xc4, 0x3d, 0x17, 0x24, 0xa3, 0xa8, 0xc0, 0x32, 0x8a, 0xea, 0x33, 0x67, 0x0, 0x6e, 0xc, 0x94, 0x5e, 0xe2, 0x46, 0x11, 0x3a, 0x0, 0x82, 0x57, 0x1, 0x98, 0xbf, 0xb, 0xa4, 0xf6, 0x55, 0xd4, 0x2a, 0xe1, 0x0, 0x40, 0xf5, 0xf3, 0xa5, 0xd3, 0x16, 0x6a, 0xb4, 0xa7, 0x19, 0xfa, 0x4f, 0x18, 0xe8, 0x2c, 0x34, 0xfb, 0x92, 0x20, 0xbb, 0xf, 0xa3, 0x1d, 0xc0, 0xcd, 0xe7, 0xb7, 0x83, 0xf9, 0xf2, 0x24, 0xd3, 0xd7, 0xaf, 0x40, 0x9a, 0x84, 0x1, 0xf0, 0xfe, 0xf6, 0xee, 0x1d, 0x80, 0x4f, 0xff, 0xc8, 0xdf, 0x63, 0xeb, 0xfd, 0x6f, 0x3, 0x74, 0x35, 0xa7, 0x2a, 0xf0, 0x17, 0xed, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0, 0x20, 0x8, 0x6, 0x0, 0x0, 0x0, 0x73, 0x7a, 0x7a, 0xf4, 0x0, 0x0, 0x2, 0x7f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0x91, 0x16, 0x97, 0x30, 0x63, 0x60, 0x60, 0x38, 0xc9, 0x30, 0x30, 0xc0, 0x9c, 0x11, 0xe8, 0x80, 0xff, 0x6b, 0x3, 0x7f, 0xd, 0x88, 0xed, 0xc1, 0xeb, 0xd9, 0x18, 0x58, 0x60, 0x1c, 0x9e, 0xac, 0xdd, 0x0, 0x5a, 0xcb, 0x6, 0xc5, 0x99, 0x23, 0x6, 0xa2, 0xaf, 0xe4, 0xb3, 0xe5, 0x8a, 0x39, 0x69, 0xf8, 0xcf, 0xa8, 0x82, 0x2d, 0x52, 0xe0, 0x1e, 0x61, 0x63, 0xe0, 0x93, 0x29, 0x7a, 0x66, 0xdb, 0xdb, 0x7a, 0x5d, 0x92, 0x96, 0x45, 0x12, 0x55, 0xf, 0x24, 0xbd, 0x4, 0x50, 0x22, 0x81, 0x98, 0x70, 0x96, 0x63, 0x2b, 0x91, 0x3d, 0xdb, 0x80, 0xb0, 0xfd, 0x52, 0xf7, 0x85, 0x6d, 0xfe, 0xf9, 0xfb, 0x2f, 0x0, 0x2, 0x80, 0x18, 0x80, 0xa7, 0x4a, 0xa8, 0x6a, 0x40, 0xf8, 0x15, 0xc0, 0x9c, 0x61, 0x43, 0x77, 0xd3, 0xd, 0x48, 0x34, 0xce, 0x5e, 0x0, 0x84, 0xd0, 0x24, 0xe7, 0xf1, 0xa8, 0x17, 0x0, 0x3, 0x94, 0x7d, 0xef, 0x1c, 0xec, 0xe, 0x98, 0x38, 0x60, 0x33, 0xc7, 0x34, 0xb6, 0x90, 0xb5, 0x1, 0xf0, 0x76, 0xfb, 0x47, 0x3d, 0xe6, 0x59, 0x62, 0x89, 0x5, 0x60, 0x8f, 0xb1, 0x7d, 0x70, 0x6a, 0x9c, 0x20, 0xf1, 0x5e, 0x82, 0x49, 0x5c, 0xff, 0x27, 0x7f, 0xcc, 0x73, 0x1c, 0xd0, 0x6f, 0xe, 0xb4, 0x3b, 0x0, 0x52, 0x3, 0x35, 0x4e, 0x94, 0xa0, 0x37, 0x0, 0x9b, 0xa4, 0x18, 0x37, 0x5e, 0xd2, 0xe8, 0xd3, 0x2d, 0xd7, 0xbd, 0x52, 0x61, 0x3b, 0x97, 0x3b, 0x5c, 0xb9, 0x3, 0x98, 0xb1, 0xa, 0x8c, 0x34, 0xeb, 0x68, 0xef, 0xc2, 0x9f, 0x22, 0xc, 0x4e, 0xf2, 0x80, 0x42, 0xa8, 0x4e, 0xdd, 0x89, 0x8f, 0x50, 0xb4, 0x84, 0x9d, 0xbd, 0xb7, 0x33, 0x6d, 0xc0, 0x7b, 0x9, 0xc8, 0x17, 0xdf, 0x13, 0x4b, 0xca, 0xf3, 0x2f, 0xe, 0x24, 0x69, 0x8e, 0xf7, 0x68, 0x2d, 0x81, 0xfb, 0xa9, 0xfc, 0xe2, 0xbc, 0x73, 0xdc, 0x51, 0x7c, 0x1d, 0x9, 0xdd, 0x1, 0x72, 0xb6, 0x59, 0x1, 0x26, 0xe, 0xc2, 0xb8, 0x85, 0xf7, 0xe, 0xd8, 0x71, 0xe2, 0x9e, 0x6e, 0xae, 0x8e, 0x18, 0x2d, 0x0, 0x9, 0x1f, 0xd2, 0xbd, 0x17, 0xb4, 0x14, 0xc2, 0xc7, 0x29, 0x2, 0x33, 0x9f, 0x1c, 0xc5, 0xbc, 0x3, 0x5b, 0x9, 0x8c, 0xf9, 0xe2, 0x80, 0xff, 0xa0, 0x3, 0x53, 0x27, 0xe1, 0x6e, 0xac, 0x26, 0x3d, 0x60, 0x2d, 0x37, 0x36, 0xb9, 0x26, 0xc7, 0xa3, 0xd9, 0x9a, 0x2e, 0xea, 0xa7, 0x7a, 0x3, 0x38, 0x8, 0x23, 0xb8, 0x25, 0x51, 0x3a, 0xfb, 0xc3, 0x5c, 0x2c, 0x0, 0xf0, 0x69, 0xa, 0xce, 0x8f, 0x47, 0x5b, 0x18, 0x7f, 0x9f, 0x46, 0x3, 0x6f, 0x73, 0xff, 0xb5, 0x4, 0x26, 0xf5, 0x62, 0x1f, 0x43, 0xbc, 0x81, 0xa4, 0x3f, 0x12, 0xeb, 0x18, 0xd2, 0x74, 0x37, 0xf6, 0xe8, 0xcb, 0x1f, 0xa2, 0x88, 0x3d, 0x16, 0x1e, 0xed, 0x25, 0x38, 0xc5, 0x5e, 0x82, 0xd3, 0x2d, 0x13, 0x89, 0x25, 0x74, 0x47, 0xf0, 0xfb, 0x9e, 0xf1, 0x32, 0x86, 0x29, 0xc6, 0xe2, 0x0, 0xd, 0xae, 0x1f, 0x1d, 0x30, 0x9, 0x2d, 0xf6, 0x47, 0xcd, 0xc8, 0x23, 0x3e, 0x4c, 0x41, 0x77, 0x53, 0xae, 0x2f, 0x0, 0xbe, 0x97, 0xc0, 0xb7, 0xbd, 0xfb, 0x8, 0x76, 0x20, 0x56, 0x80, 0x50, 0x32, 0x5f, 0x46, 0x12, 0x68, 0xf6, 0x24, 0xa1, 0xb5, 0xf9, 0xd7, 0x9f, 0x25, 0xc9, 0x9c, 0x75, 0x81, 0x1b, 0x3e, 0x4f, 0xc1, 0xe8, 0x24, 0x16, 0x42, 0xd2, 0x40, 0x1c, 0xd9, 0xb6, 0x26, 0xc, 0xa4, 0x58, 0x1b, 0x70, 0x3e, 0x2c, 0x0, 0xdd, 0xb8, 0x8a, 0x76, 0x73, 0x5d, 0x57, 0x32, 0xc9, 0x45, 0xfe, 0x23, 0x3a, 0x2c, 0x8, 0x52, 0x32, 0xef, 0x0, 0xdd, 0x7e, 0x9d, 0xd9, 0xbe, 0xc6, 0xe5, 0xbe, 0xd6, 0x31, 0x1c, 0x88, 0x16, 0xad, 0xa2, 0x74, 0xd1, 0xae, 0x24, 0x95, 0xc4, 0xad, 0x6, 0xb, 0x0, 0x59, 0x1c, 0x67, 0xe7, 0x5c, 0x33, 0x6b, 0xef, 0x25, 0x68, 0x37, 0x58, 0xa8, 0x5, 0xfa, 0x17, 0x28, 0xaa, 0x1a, 0xa9, 0x96, 0x46, 0x77, 0x1c, 0xf8, 0x16, 0x71, 0xa0, 0x2f, 0xfc, 0x5a, 0xe7, 0x5d, 0x6b, 0x13, 0x76, 0x73, 0x89, 0x38, 0x72, 0x35, 0x1, 0x10, 0xfa, 0x9, 0x20, 0xe, 0xa4, 0xa9, 0x9f, 0xba, 0xc6, 0x5, 0x2f, 0x0, 0x6d, 0x43, 0x77, 0x6c, 0xab, 0x66, 0x6c, 0xa7, 0x7f, 0x73, 0x60, 0x77, 0x21, 0xe7, 0xf7, 0x53, 0x36, 0x75, 0x2, 0xfc, 0x37, 0x96, 0x15, 0xd1, 0x28, 0xc6, 0xff, 0x65, 0xa0, 0xd, 0x60, 0x2, 0x63, 0x4, 0x0, 0xf5, 0x8e, 0x13, 0x81, 0xf4, 0x3c, 0x86, 0x81, 0x1, 0x49, 0x0, 0x33, 0xd4, 0x35, 0xaa, 0x8d, 0x7e, 0xfe, 0xa5, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_cursor_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc6, 0x50, 0x4c, 0x54, 0x45, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9c, 0xd4, 0xac, 0x9e, 0xd5, 0xaf, 0xa3, 0xd5, 0xb0, 0xa3, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xb0, 0xa3, 0xd6, 0xad, 0xa0, 0xd6, 0xad, 0xa0, 0xd5, 0xb0, 0xa3, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa5, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xdb, 0xb7, 0xad, 0xda, 0xb8, 0xae, 0xdb, 0xb9, 0xad, 0xdb, 0xb9, 0xad, 0xdb, 0xb7, 0xad, 0xdd, 0xba, 0xb1, 0xdd, 0xbb, 0xb1, 0xdd, 0xbd, 0xb1, 0xdd, 0xbf, 0xb3, 0xdd, 0xbd, 0xb3, 0xdf, 0xc1, 0xb7, 0xdf, 0xc0, 0xb5, 0xdf, 0xbf, 0xb5, 0xe1, 0xc3, 0xb9, 0xe1, 0xc3, 0xbb, 0xe1, 0xc5, 0xbb, 0xe2, 0xc7, 0xbe, 0xe1, 0xc5, 0xbd, 0xe4, 0xcb, 0xc2, 0xe3, 0xca, 0xc1, 0xe3, 0xcb, 0xc3, 0xe6, 0xce, 0xc6, 0xe6, 0xd0, 0xc6, 0xe8, 0xd1, 0xca, 0xe8, 0xd1, 0xca, 0xe8, 0xd0, 0xca, 0xe8, 0xcf, 0xca, 0xb7, 0x7d, 0x69, 0xb1, 0x77, 0x63, 0xac, 0x73, 0x5c, 0xa6, 0x69, 0x56, 0x9c, 0x67, 0x54, 0x93, 0x62, 0x51, 0x88, 0x60, 0x50, 0x0, 0x0, 0x0, 0x39, 0x76, 0x1d, 0xc2, 0x0, 0x0, 0x0, 0x3a, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x33, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x2f, 0x2f, 0xb8, 0xf, 0x95, 0x41, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x41, 0x89, 0xde, 0x6c, 0x4e, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x9e, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0xcf, 0x5b, 0x17, 0x81, 0x40, 0x14, 0x5, 0xe0, 0xe3, 0x9a, 0x4b, 0x2e, 0x31, 0x14, 0x62, 0x22, 0x53, 0x4d, 0x83, 0x44, 0xc, 0xa6, 0xa9, 0xf9, 0xff, 0xbf, 0xca, 0xd4, 0x5a, 0x1e, 0x7c, 0xfb, 0xec, 0xb5, 0x9f, 0xf, 0x7c, 0xfe, 0x80, 0x80, 0x86, 0xd6, 0x6c, 0x69, 0xed, 0x8e, 0x80, 0xbc, 0x6b, 0x18, 0xbd, 0xfe, 0x60, 0x68, 0x9a, 0xa3, 0xf1, 0x24, 0x7, 0x39, 0xb5, 0x2c, 0x6b, 0x36, 0x47, 0x68, 0x81, 0xd0, 0x52, 0x42, 0x61, 0x3b, 0xb6, 0xb3, 0x72, 0xd6, 0x1b, 0x77, 0xeb, 0xee, 0xa, 0x28, 0x31, 0xc6, 0x9e, 0x87, 0x3d, 0xbc, 0x3f, 0xf8, 0x7e, 0x9, 0xea, 0x48, 0x8, 0x9, 0xc2, 0x28, 0x22, 0x21, 0x9, 0x14, 0x28, 0x1a, 0x33, 0x16, 0xd3, 0x98, 0xb2, 0x98, 0x51, 0x5, 0xe5, 0x49, 0x3b, 0xeb, 0x5e, 0x74, 0x4a, 0x28, 0x92, 0xca, 0xb5, 0xbe, 0xa4, 0x0, 0x99, 0xde, 0xd2, 0xca, 0xbd, 0x5a, 0x9, 0x79, 0x96, 0x3d, 0xb2, 0x9f, 0x1c, 0xc4, 0x93, 0xf3, 0x17, 0xaf, 0xfb, 0xe6, 0x2, 0xfe, 0x5f, 0xf8, 0x2, 0x30, 0xbc, 0x1f, 0xb4, 0x2b, 0xfc, 0x80, 0xca, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9e, 0xd3, 0xaa, 0x9d, 0xd4, 0xab, 0x9c, 0xd4, 0xac, 0x9e, 0xd5, 0xaf, 0xa3, 0xd5, 0xb0, 0xa3, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xaf, 0xa3, 0xd5, 0xad, 0xa1, 0xd5, 0xb0, 0xa3, 0xd6, 0xad, 0xa0, 0xd6, 0xad, 0xa0, 0xd5, 0xb0, 0xa3, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa7, 0xd7, 0xb1, 0xa5, 0xd7, 0xb1, 0xa5, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xd8, 0xb5, 0xaa, 0xda, 0xb3, 0xa8, 0xd8, 0xb3, 0xa8, 0xdb, 0xb7, 0xad, 0xda, 0xb8, 0xae, 0xdb, 0xb9, 0xad, 0xdb, 0xb9, 0xad, 0xdb, 0xb7, 0xad, 0xdd, 0xba, 0xb1, 0xdd, 0xbb, 0xb1, 0xdd, 0xbd, 0xb1, 0xdd, 0xbf, 0xb3, 0xdd, 0xbd, 0xb3, 0xdf, 0xc1, 0xb7, 0xdf, 0xc0, 0xb5, 0xdf, 0xbf, 0xb5, 0xe1, 0xc3, 0xb9, 0xe1, 0xc3, 0xbb, 0xe1, 0xc5, 0xbb, 0xe2, 0xc7, 0xbe, 0xe1, 0xc5, 0xbd, 0xe4, 0xcb, 0xc2, 0xe3, 0xca, 0xc1, 0xe3, 0xcb, 0xc3, 0xe6, 0xce, 0xc6, 0xe6, 0xd0, 0xc6, 0xe8, 0xd1, 0xca, 0xe8, 0xd1, 0xca, 0xe8, 0xd0, 0xca, 0xe8, 0xcf, 0xca, 0xb7, 0x7d, 0x69, 0xb1, 0x77, 0x63, 0xac, 0x73, 0x5c, 0xa6, 0x69, 0x56, 0x9c, 0x67, 0x54, 0x93, 0x62, 0x51, 0x88, 0x60, 0x50, 0x9e, 0xe4, 0xa3, 0x87, 0x0, 0x0, 0x0, 0x3a, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x33, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x2f, 0x2f, 0xb8, 0xf, 0x95, 0x41, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x4d, 0xc9, 0x1, 0xa, 0x2, 0x31, 0xc, 0x44, 0xd1, 0xff, 0xdb, 0xec, 0x2a, 0x1e, 0x48, 0xc0, 0xfb, 0x7b, 0x2c, 0x3b, 0x96, 0x2c, 0x88, 0x3, 0x19, 0x78, 0x19, 0x5f, 0xfc, 0xa7, 0x7c, 0xb, 0x78, 0xd5, 0xb3, 0x3c, 0x45, 0xf5, 0xea, 0xf2, 0x21, 0xb4, 0xc2, 0xd8, 0xbc, 0x19, 0xcd, 0xb0, 0xab, 0xbc, 0x83, 0xa4, 0x1f, 0x6c, 0x1e, 0x82, 0xca, 0x67, 0x2c, 0x2d, 0xe, 0x25, 0x31, 0x67, 0x6a, 0x51, 0x99, 0xc0, 0xc8, 0xbe, 0x35, 0xcc, 0x45, 0xc, 0xca, 0xdc, 0x1c, 0x6, 0x70, 0x8f, 0xa1, 0xd7, 0x36, 0x13, 0xe8, 0xb5, 0x6d, 0x18, 0x6b, 0xb3, 0xf8, 0x65, 0xe6, 0xb, 0x36, 0x5c, 0x24, 0xde, 0x86, 0x96, 0x3a, 0xaf, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_cursor_unfocus_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xbf, 0xb5, 0xb1, 0xc0, 0xb5, 0xb2, 0xc3, 0xb8, 0xb5, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc5, 0xba, 0xb7, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xba, 0xb7, 0xc5, 0xba, 0xb7, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xca, 0xc1, 0xbe, 0xca, 0xc1, 0xbe, 0xcd, 0xc4, 0xc1, 0xcd, 0xc6, 0xc3, 0xd0, 0xc9, 0xc6, 0xcf, 0xc8, 0xc5, 0xd2, 0xcb, 0xc8, 0xd3, 0xcb, 0xc9, 0xd3, 0xcc, 0xc9, 0xd5, 0xcd, 0xcb, 0xd4, 0xcc, 0xca, 0xd7, 0xd1, 0xcf, 0xd6, 0xd0, 0xce, 0xda, 0xd4, 0xd2, 0xdd, 0xd7, 0xd5, 0xdd, 0xd7, 0xd5, 0x9a, 0x8b, 0x86, 0x94, 0x85, 0x80, 0x8e, 0x80, 0x7a, 0x88, 0x79, 0x74, 0x81, 0x75, 0x6f, 0x7a, 0x6f, 0x6a, 0x73, 0x69, 0x65, 0x0, 0x0, 0x0, 0xfb, 0x87, 0x71, 0x8e, 0x0, 0x0, 0x0, 0x2b, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x2f, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x82, 0xd8, 0x8a, 0x2f, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x32, 0x40, 0xd2, 0x4c, 0xc8, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x4, 0x4e, 0x1d, 0x2, 0xaf, 0x0, 0x0, 0x0, 0x82, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x55, 0xcf, 0xe9, 0x16, 0xc1, 0x30, 0x14, 0x4, 0xe0, 0xb1, 0x96, 0x16, 0x25, 0x34, 0x84, 0x26, 0x2d, 0xaa, 0xb6, 0xac, 0xef, 0xff, 0x72, 0x6e, 0x38, 0xe, 0xfd, 0xe6, 0xce, 0x99, 0xdf, 0x17, 0xcf, 0xe, 0x68, 0xf4, 0x48, 0x7f, 0x40, 0x86, 0x23, 0xd, 0x33, 0x4e, 0x92, 0x64, 0x32, 0x4d, 0xb3, 0x2c, 0x9d, 0xcd, 0xd, 0xec, 0x22, 0xcf, 0xf3, 0xe5, 0x8a, 0xb1, 0x35, 0x63, 0x1b, 0xb, 0x57, 0xf0, 0x82, 0x73, 0xbe, 0xdd, 0x9, 0x21, 0xf6, 0xe, 0xfe, 0xf0, 0x55, 0x96, 0xa5, 0x47, 0x90, 0x91, 0x52, 0x4a, 0x2a, 0x29, 0x3, 0x42, 0x55, 0x93, 0xaa, 0x8e, 0x53, 0x5, 0xf8, 0x23, 0x39, 0x51, 0xcf, 0x14, 0xf, 0xd7, 0x44, 0x97, 0xf7, 0x35, 0xe, 0xb6, 0xbd, 0xb6, 0x1f, 0xb4, 0x16, 0xe6, 0xf6, 0xc7, 0x40, 0xdf, 0x1f, 0x3f, 0x1a, 0xdd, 0x17, 0x5e, 0xc0, 0x36, 0x18, 0x83, 0x7f, 0x54, 0x76, 0x87, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0xe, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x96, 0xdd, 0xe3, 0x0, 0x0, 0x0, 0x96, 0x50, 0x4c, 0x54, 0x45, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xc0, 0xb5, 0xb2, 0xbf, 0xb4, 0xb1, 0xbf, 0xb5, 0xb1, 0xc0, 0xb5, 0xb2, 0xc3, 0xb8, 0xb5, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc2, 0xb7, 0xb4, 0xc3, 0xb8, 0xb5, 0xc5, 0xba, 0xb7, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xbc, 0xb9, 0xc5, 0xba, 0xb7, 0xc5, 0xba, 0xb7, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xc7, 0xbe, 0xbb, 0xc6, 0xbd, 0xba, 0xca, 0xc1, 0xbe, 0xca, 0xc1, 0xbe, 0xcd, 0xc4, 0xc1, 0xcd, 0xc6, 0xc3, 0xd0, 0xc9, 0xc6, 0xcf, 0xc8, 0xc5, 0xd2, 0xcb, 0xc8, 0xd3, 0xcb, 0xc9, 0xd3, 0xcc, 0xc9, 0xd5, 0xcd, 0xcb, 0xd4, 0xcc, 0xca, 0xd7, 0xd1, 0xcf, 0xd6, 0xd0, 0xce, 0xda, 0xd4, 0xd2, 0xdd, 0xd7, 0xd5, 0xdd, 0xd7, 0xd5, 0x9a, 0x8b, 0x86, 0x94, 0x85, 0x80, 0x8e, 0x80, 0x7a, 0x88, 0x79, 0x74, 0x81, 0x75, 0x6f, 0x7a, 0x6f, 0x6a, 0x73, 0x69, 0x65, 0x9a, 0x51, 0xd2, 0xe3, 0x0, 0x0, 0x0, 0x2b, 0x74, 0x52, 0x4e, 0x53, 0x32, 0x2f, 0x30, 0x33, 0x38, 0x40, 0x32, 0x2f, 0x2f, 0x31, 0x33, 0x33, 0x36, 0x38, 0x31, 0x2f, 0x30, 0x31, 0x33, 0x33, 0x35, 0x2f, 0x2f, 0x30, 0x32, 0x33, 0x33, 0x2f, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x32, 0x2f, 0x82, 0xd8, 0x8a, 0x2f, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x62, 0xd1, 0x66, 0x40, 0x6, 0x2c, 0x8c, 0x57, 0x0, 0x2d, 0xc9, 0x87, 0x15, 0x4, 0x51, 0x8, 0x42, 0xd1, 0x7, 0x13, 0x3b, 0xd9, 0xfe, 0x1b, 0x1c, 0x16, 0xcf, 0xf, 0xa6, 0xab, 0x6a, 0xd3, 0x2a, 0xbf, 0x53, 0xb7, 0x66, 0xa8, 0x63, 0xe9, 0xd4, 0xbb, 0x88, 0x82, 0xcb, 0x47, 0xd9, 0xb, 0x54, 0xde, 0xec, 0x57, 0x97, 0xde, 0x63, 0x94, 0x12, 0xab, 0xec, 0xec, 0x56, 0xce, 0x69, 0x28, 0xc8, 0x9f, 0xbf, 0x9c, 0x39, 0xd8, 0x16, 0x47, 0x69, 0x65, 0xc, 0xe, 0xc3, 0x8e, 0xeb, 0x69, 0x28, 0x1, 0x0, 0xb0, 0xae, 0x0, 0x0, 0x90, 0x3f, 0xa6, 0x5b, 0x1b, 0xad, 0x12, 0x69, 0xd7, 0x5c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_title_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x23, 0x25, 0x4c, 0x4a, 0x4e, 0x1, 0xf9, 0x98, 0x2e, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x20, 0xd, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0xc7, 0xaa, 0x85, 0x8e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x25, 0x23, 0x25, 0x4c, 0x4a, 0x4e, 0x1, 0xf9, 0x98, 0x2e, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x6e, 0xa6, 0xf, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char tree_title_pressed_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x36, 0x34, 0x36, 0x4c, 0x4a, 0x4e, 0x14, 0xd7, 0x5b, 0xf8, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xc, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x20, 0xd, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0xc7, 0xaa, 0x85, 0x8e, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x1, 0x3, 0x0, 0x0, 0x0, 0x25, 0x3d, 0x6d, 0x22, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x36, 0x34, 0x36, 0x4c, 0x4a, 0x4e, 0x14, 0xd7, 0x5b, 0xf8, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0x0, 0x0, 0x0, 0x30, 0x0, 0x1, 0x6e, 0xa6, 0xf, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char unchecked_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x36, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0xff, 0xff, 0xff, 0xf7, 0x93, 0x46, 0x7a, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x11, 0xe2, 0xb5, 0x3d, 0xba, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x53, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0xb5, 0xcf, 0xc1, 0x12, 0x80, 0x20, 0x8, 0x45, 0x51, 0x5, 0x14, 0xd, 0x5, 0xff, 0xff, 0x6b, 0x23, 0x27, 0x67, 0x9a, 0x6c, 0xdb, 0x5d, 0x9e, 0xd, 0x8f, 0x10, 0xb6, 0x22, 0x20, 0xa5, 0x19, 0x21, 0x44, 0x7, 0xc8, 0x2c, 0x6d, 0x26, 0x9c, 0xc1, 0x1, 0xb9, 0xab, 0xcd, 0xb4, 0x33, 0x3a, 0x90, 0xe8, 0xb8, 0x53, 0x21, 0x87, 0xd4, 0x6c, 0x81, 0xb5, 0xf4, 0x17, 0x6c, 0x67, 0x9f, 0xc3, 0xca, 0x35, 0xc, 0x6a, 0x59, 0xd3, 0x8f, 0xa, 0x5f, 0xcf, 0xbd, 0x3a, 0x1, 0x93, 0xe2, 0x8, 0xa4, 0xb1, 0xeb, 0xd3, 0x56, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x23, 0xc3, 0x49, 0x39, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0xcf, 0x45, 0x2, 0x80, 0x40, 0x8, 0x0, 0x40, 0x97, 0x66, 0xfb, 0xff, 0x9f, 0xb5, 0xdb, 0xb3, 0x73, 0xa4, 0x19, 0xbe, 0x2, 0x20, 0xf1, 0x8a, 0x10, 0xc2, 0x1c, 0x0, 0xd1, 0x94, 0x57, 0x49, 0x5, 0xe6, 0x0, 0x6a, 0xa9, 0x6d, 0x55, 0x8b, 0xe2, 0x1c, 0xa0, 0x54, 0xfb, 0xae, 0x26, 0x9a, 0x3, 0x9c, 0xdb, 0x11, 0x68, 0x99, 0xff, 0xa, 0x7c, 0xd6, 0xde, 0xf, 0x33, 0x9c, 0x3, 0xe0, 0x76, 0x9c, 0x1e, 0x1d, 0xbe, 0xcf, 0x7d, 0x4c, 0x93, 0xe2, 0x8, 0xa4, 0x66, 0x3c, 0xec, 0xed, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char updown_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x2b, 0x8a, 0x3e, 0x7d, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0xa6, 0x49, 0x44, 0x41, 0x54, 0x28, 0x91, 0xa5, 0x90, 0x21, 0xe, 0xc2, 0x50, 0x10, 0x44, 0xdf, 0x27, 0x9b, 0x10, 0x2e, 0xc0, 0x9, 0xd6, 0x81, 0xe3, 0x6, 0xe0, 0xa0, 0xd7, 0x2d, 0xae, 0x18, 0x24, 0x95, 0xc5, 0x7d, 0x51, 0xdd, 0xb, 0x60, 0xf6, 0x67, 0x31, 0xfb, 0x49, 0xc1, 0x20, 0x3a, 0x6a, 0x93, 0x99, 0x9d, 0xcc, 0xc, 0x2c, 0x45, 0xaa, 0x47, 0xce, 0x79, 0x2b, 0x22, 0x2d, 0x80, 0x99, 0x5d, 0x54, 0x75, 0xfa, 0x8, 0x82, 0xec, 0x80, 0x7d, 0xe8, 0x7, 0x33, 0x3b, 0xa9, 0xea, 0x94, 0x82, 0xbc, 0x1, 0x3b, 0x60, 0x8, 0xc1, 0x1e, 0x78, 0x9a, 0xd9, 0x51, 0xc2, 0x76, 0x57, 0xbf, 0x0, 0xaa, 0x9b, 0x88, 0xb4, 0x2b, 0x77, 0x7f, 0x1, 0x7d, 0xb5, 0x54, 0xd5, 0x29, 0x84, 0x7d, 0x70, 0x4b, 0x6b, 0x8e, 0xe3, 0x78, 0x7, 0x36, 0x66, 0x76, 0xae, 0xd5, 0x22, 0xf8, 0x15, 0x78, 0x89, 0xbb, 0xaf, 0x53, 0x4a, 0x7, 0x11, 0xe9, 0x72, 0xce, 0x5f, 0x21, 0xdd, 0xfd, 0x21, 0xa5, 0x94, 0x66, 0x96, 0xba, 0x9b, 0xd5, 0x1c, 0x4a, 0x29, 0xcd, 0xff, 0xa1, 0x7e, 0xa6, 0xbe, 0xc6, 0xd4, 0x9f, 0x3c, 0xcb, 0xf1, 0x6, 0x8e, 0x4e, 0x65, 0x44, 0x6f, 0x74, 0x5c, 0xa1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0x81, 0x83, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0x4e, 0xb5, 0x1, 0xc0, 0x30, 0xc, 0xf3, 0x15, 0xfe, 0xff, 0x96, 0x64, 0xa, 0x6c, 0xca, 0x56, 0xd2, 0x25, 0x65, 0xe6, 0xc8, 0x8b, 0x49, 0x20, 0x79, 0x28, 0x95, 0x81, 0xa1, 0xd4, 0x7d, 0x4, 0xbb, 0xa1, 0x50, 0xea, 0x3c, 0xa6, 0x71, 0x98, 0x96, 0x69, 0x58, 0x31, 0xcc, 0xb7, 0xe5, 0x2f, 0x48, 0x63, 0x26, 0xf6, 0xa2, 0xd4, 0x18, 0xf9, 0x7, 0x2d, 0xe3, 0x46, 0x89, 0xb4, 0xd2, 0xf8, 0xa3, 0x68, 0xe3, 0xd7, 0x14, 0x20, 0xe6, 0xc3, 0x3d, 0xd8, 0xca, 0x5e, 0x94, 0x32, 0xd0, 0x3, 0x91, 0xba, 0x5f, 0x1b, 0x4a, 0x9b, 0x12, 0x62, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vseparator_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0xc, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xff, 0xff, 0xff, 0x64, 0x6c, 0x1, 0xd2, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x3, 0x11, 0xc, 0x4c, 0xf2, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x10, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x80, 0x81, 0xac, 0x95, 0xc, 0x48, 0x0, 0x0, 0xe, 0x79, 0x1, 0x14, 0xa1, 0xc9, 0x59, 0x2, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x2, 0x3, 0x0, 0x0, 0x0, 0xb9, 0x61, 0x56, 0x18, 0x0, 0x0, 0x0, 0x9, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x73, 0x9b, 0xaa, 0xce, 0xdc, 0xe1, 0xeb, 0x64, 0x9a, 0x78, 0x0, 0x0, 0x0, 0x3, 0x74, 0x52, 0x4e, 0x53, 0x0, 0xb3, 0xb3, 0x67, 0xf6, 0xdb, 0x93, 0x0, 0x0, 0x0, 0xf, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x80, 0x83, 0xac, 0x95, 0xc, 0x48, 0x0, 0x0, 0xe, 0x79, 0x1, 0x14, 0x17, 0x9a, 0x55, 0x26, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vslider_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x54, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x34, 0x33, 0x3a, 0x2d, 0x2c, 0x32, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x40, 0x3e, 0x4a, 0x20, 0x20, 0x24, 0x34, 0x33, 0x3a, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x27, 0x2d, 0x2c, 0x32, 0x1f, 0x1f, 0x23, 0xff, 0xff, 0xff, 0x3, 0x35, 0xf1, 0x5f, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1a, 0x40, 0x5d, 0x19, 0x28, 0x96, 0xf0, 0xfd, 0x94, 0x95, 0xfc, 0x93, 0xfc, 0xc0, 0x0, 0xb4, 0xa, 0x5f, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1b, 0x2, 0x60, 0xd4, 0xa4, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x64, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x9d, 0xcf, 0x39, 0x2, 0x80, 0x20, 0x10, 0x3, 0xc0, 0xe5, 0x90, 0x43, 0x50, 0x94, 0x1b, 0xfe, 0xff, 0x50, 0x5, 0x69, 0x94, 0xce, 0x94, 0x53, 0xec, 0x26, 0x0, 0x0, 0x88, 0x2e, 0x8c, 0x73, 0x26, 0x28, 0x82, 0x1e, 0x44, 0xe5, 0xaa, 0xb4, 0x56, 0x9b, 0x1c, 0x82, 0xc4, 0x6e, 0x9c, 0xf7, 0xce, 0x1c, 0x62, 0x0, 0x53, 0x2e, 0xc4, 0x18, 0x9c, 0x62, 0x3, 0xb8, 0xf6, 0xf1, 0x8e, 0x3f, 0xf9, 0x3, 0xd8, 0xa6, 0xdc, 0x20, 0x27, 0x8b, 0x3b, 0x90, 0x52, 0x43, 0x83, 0x50, 0xb, 0xf9, 0xb, 0xd3, 0xd1, 0xe9, 0xed, 0x5c, 0x6c, 0xaa, 0xfe, 0x1d, 0xf7, 0x9e, 0x7f, 0x1, 0x89, 0x5c, 0xa, 0x6b, 0x1f, 0xe5, 0xca, 0x60, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x51, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x34, 0x33, 0x3a, 0x2d, 0x2c, 0x32, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x40, 0x3e, 0x4a, 0x20, 0x20, 0x24, 0x34, 0x33, 0x3a, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x1e, 0x1e, 0x23, 0x23, 0x23, 0x27, 0x2d, 0x2c, 0x32, 0x1f, 0x1f, 0x23, 0x30, 0x7, 0x9c, 0xfe, 0x0, 0x0, 0x0, 0x13, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x4, 0x1a, 0x40, 0x5d, 0x19, 0x28, 0x96, 0xf0, 0xfd, 0x94, 0x95, 0xfc, 0x93, 0xfc, 0xc0, 0x0, 0xb4, 0xa, 0x5f, 0x0, 0x0, 0x0, 0x5f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x2c, 0xc8, 0x83, 0x11, 0x0, 0x30, 0x0, 0xc0, 0xc0, 0xda, 0xf6, 0xfe, 0x8b, 0xd6, 0x39, 0xe6, 0xc1, 0xe, 0x12, 0xca, 0x38, 0x67, 0x82, 0xc0, 0x73, 0xe7, 0xa5, 0xd2, 0xc6, 0x68, 0x2b, 0xbf, 0x40, 0xe1, 0x7c, 0x2e, 0x25, 0xfb, 0x20, 0x3e, 0x30, 0x9d, 0x6b, 0x6b, 0x35, 0x6b, 0xf6, 0x81, 0x9b, 0xd2, 0x76, 0x25, 0xf2, 0x7, 0x28, 0xf5, 0x71, 0x60, 0xf4, 0x84, 0x2e, 0xe0, 0x35, 0x49, 0x29, 0x51, 0x90, 0x80, 0xa8, 0x94, 0x24, 0x33, 0x19, 0x2, 0x18, 0x86, 0xa2, 0x5b, 0x8b, 0xe9, 0x30, 0x4c, 0xa7, 0x63, 0x7a, 0xe, 0xc3, 0xfb, 0x0, 0x89, 0x5c, 0xa, 0x6b, 0x4f, 0x78, 0xac, 0x83, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vslider_grabber_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xb7, 0xff, 0x88, 0x5, 0x1d, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x1, 0x12, 0x1, 0x36, 0x8, 0x50, 0xb9, 0xa7, 0x53, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0xf6, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0xbd, 0x90, 0xb1, 0x4a, 0x42, 0x51, 0x0, 0x86, 0xbf, 0x73, 0x8e, 0x71, 0xe5, 0x9a, 0x5c, 0x41, 0xd0, 0x66, 0x6b, 0x33, 0x1c, 0x7c, 0x80, 0xa0, 0xa5, 0x17, 0x8, 0xa2, 0x2d, 0x84, 0xf0, 0x1, 0xa2, 0x25, 0xf1, 0x9, 0x9a, 0x1c, 0xda, 0x5b, 0xb2, 0x47, 0xa8, 0xa5, 0xc1, 0xa0, 0x51, 0x88, 0xa2, 0x29, 0xa, 0xc1, 0x84, 0x8, 0x43, 0xf4, 0x96, 0x17, 0xcf, 0xed, 0xde, 0x73, 0x9c, 0xcc, 0x5c, 0xda, 0xea, 0x9f, 0x3f, 0xfe, 0x9f, 0xef, 0x87, 0x3f, 0x8f, 0x0, 0x40, 0xe1, 0xe2, 0x91, 0x42, 0x10, 0x32, 0xe6, 0x3, 0x8d, 0xc1, 0xce, 0x1, 0x45, 0xb6, 0xba, 0xbb, 0xba, 0xed, 0x95, 0x8c, 0xd0, 0x7d, 0xff, 0xe1, 0xee, 0xe2, 0xb6, 0xdd, 0x79, 0x61, 0xc4, 0xd7, 0xc, 0x48, 0x57, 0x2b, 0xeb, 0xb5, 0x28, 0xaf, 0x1, 0xc5, 0x12, 0x4e, 0xac, 0x7b, 0x6f, 0x57, 0x27, 0x8d, 0xcf, 0xe, 0x1, 0x56, 0x1, 0xb9, 0x9d, 0xba, 0x28, 0x6, 0x18, 0xc, 0x31, 0x21, 0x5a, 0xda, 0x4c, 0xb6, 0xbc, 0xb9, 0x35, 0x7c, 0xea, 0xbd, 0x13, 0x4a, 0x20, 0xe5, 0x95, 0xf4, 0x6c, 0x12, 0x30, 0x84, 0xf8, 0x44, 0x6b, 0xfb, 0xcd, 0x83, 0x3d, 0x1c, 0xf9, 0x8b, 0x80, 0x4a, 0xba, 0x88, 0x4, 0x30, 0x1e, 0xdd, 0x3b, 0x1b, 0xf1, 0x77, 0x87, 0x24, 0x81, 0x8b, 0x79, 0x3e, 0x3b, 0x6a, 0x5d, 0x33, 0x51, 0x80, 0x2d, 0x38, 0x2b, 0x65, 0xb5, 0x6c, 0x91, 0x28, 0x92, 0xa4, 0xad, 0xec, 0x76, 0xcf, 0x8f, 0xf, 0x1f, 0xdb, 0xc, 0x31, 0xb, 0x9a, 0xb1, 0xd0, 0x3, 0xfb, 0xda, 0x3a, 0xbd, 0xbc, 0x89, 0xfa, 0xf8, 0x73, 0xcd, 0x9f, 0x47, 0x45, 0x4, 0xf8, 0x4, 0x18, 0xfe, 0x2f, 0x53, 0x8, 0x62, 0x5c, 0xcf, 0x1f, 0x5f, 0xcb, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xbc, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x17, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0xd2, 0xf2, 0x3a, 0xf, 0xce, 0x78, 0x3f, 0xed, 0x43, 0xff, 0xed, 0xc6, 0xf5, 0x41, 0xa9, 0x8a, 0x86, 0xc, 0x22, 0xc, 0xac, 0x8, 0x5, 0xbc, 0x69, 0x79, 0x93, 0x5e, 0xf4, 0xfd, 0x6f, 0x7, 0xc2, 0xae, 0xff, 0xfd, 0xff, 0xa7, 0xfd, 0xe9, 0x7f, 0x50, 0x31, 0x87, 0x47, 0x87, 0x81, 0x1b, 0x66, 0x8e, 0x4c, 0xe7, 0xc1, 0xbe, 0xff, 0x2d, 0xff, 0x9b, 0xa1, 0xb0, 0xf5, 0x7f, 0xe7, 0xff, 0xc9, 0xff, 0x27, 0xdc, 0xb6, 0xf0, 0x7, 0x9a, 0xc3, 0x2, 0x52, 0xa0, 0x3e, 0xe3, 0x7d, 0x3b, 0x54, 0x12, 0xa1, 0xa8, 0xe7, 0xff, 0x9c, 0x2f, 0x45, 0xc5, 0xc, 0xdc, 0xf8, 0x14, 0x7c, 0xaf, 0xaa, 0x65, 0xe0, 0xc1, 0x69, 0xc5, 0xc4, 0x3b, 0xe, 0xa1, 0xc, 0x62, 0xc, 0x2c, 0x68, 0x8e, 0xec, 0xf8, 0xdf, 0xfb, 0x7f, 0xda, 0xbf, 0x89, 0xf, 0x4a, 0xa6, 0xf2, 0xe8, 0x0, 0x75, 0x33, 0xa2, 0x79, 0x73, 0xea, 0x87, 0xbe, 0x7b, 0xbd, 0x47, 0x7d, 0x53, 0x58, 0x34, 0x18, 0x84, 0x19, 0x58, 0xb1, 0x7, 0x94, 0xa, 0x83, 0x14, 0x50, 0x27, 0x13, 0x3, 0x3d, 0x1, 0x0, 0x79, 0xc3, 0x79, 0x54, 0x19, 0x56, 0x3b, 0x28, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vslider_grabber_disabled_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x7, 0xa, 0x13, 0x2e, 0x39, 0x86, 0x33, 0xc2, 0xfe, 0x0, 0x0, 0x0, 0x1d, 0x69, 0x54, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x0, 0x0, 0x0, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x64, 0x2e, 0x65, 0x7, 0x0, 0x0, 0x0, 0xb7, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0xa0, 0x13, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0x8c, 0xf3, 0x5c, 0xf, 0xfa, 0xbc, 0xf7, 0xfe, 0xe0, 0x71, 0xdb, 0x71, 0xbd, 0x66, 0xaa, 0xa0, 0x21, 0x83, 0x8, 0x3, 0x2b, 0x42, 0x1, 0xaf, 0x71, 0x9e, 0xe7, 0xb, 0xf7, 0xff, 0x2e, 0x40, 0xe8, 0xfa, 0xdf, 0xe3, 0xbf, 0xf7, 0x1f, 0x8f, 0x7, 0x36, 0x73, 0xd8, 0x74, 0x18, 0xb8, 0x61, 0xe6, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x87, 0xce, 0x40, 0x65, 0x5e, 0xff, 0x3d, 0x6e, 0xcb, 0xf8, 0x3, 0xcd, 0x61, 0x1, 0x29, 0x50, 0xf7, 0x79, 0xef, 0x82, 0xa4, 0x0, 0xa2, 0xc8, 0xed, 0xbf, 0xdf, 0x17, 0xcb, 0x62, 0xa0, 0x29, 0x78, 0x14, 0x7c, 0xb7, 0xad, 0x65, 0xe0, 0xc1, 0x69, 0x85, 0xe7, 0x1d, 0x85, 0x50, 0x6, 0x31, 0x88, 0x15, 0x48, 0x8e, 0x74, 0xf9, 0xef, 0xfe, 0xdf, 0xfb, 0x9f, 0xe7, 0x3, 0xab, 0xa9, 0x40, 0x47, 0xf2, 0xc0, 0x1c, 0x89, 0xe4, 0x4d, 0xf7, 0x7b, 0xee, 0x47, 0xd5, 0x53, 0x98, 0x34, 0x18, 0x84, 0x91, 0xbd, 0x89, 0x1c, 0x50, 0x2a, 0xc, 0x52, 0x40, 0x9d, 0x4c, 0xc, 0xf4, 0x4, 0x0, 0xf1, 0x9, 0x63, 0x9b, 0x3e, 0x2a, 0x19, 0x52, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0xb4, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x17, 0x60, 0x66, 0xe0, 0x65, 0x90, 0x61, 0x50, 0x67, 0xd0, 0x60, 0x50, 0x62, 0x10, 0x67, 0xe0, 0x2, 0xf2, 0x19, 0x51, 0xa5, 0xc5, 0x8c, 0xf3, 0x5c, 0xf, 0xfa, 0xbc, 0xf7, 0xfe, 0xe0, 0x71, 0xdb, 0x71, 0xbd, 0x66, 0xaa, 0xa0, 0x21, 0x83, 0x8, 0x3, 0x2b, 0x42, 0x1, 0xaf, 0x71, 0x9e, 0xe7, 0xb, 0xf7, 0xff, 0x2e, 0x40, 0xe8, 0xfa, 0xdf, 0xe3, 0xbf, 0xf7, 0x1f, 0x8f, 0x7, 0x36, 0x73, 0xd8, 0x74, 0x18, 0xb8, 0x61, 0xe6, 0xc8, 0xb8, 0x1e, 0x74, 0xff, 0xef, 0x4, 0x87, 0xce, 0x40, 0x65, 0x5e, 0xff, 0x3d, 0x6e, 0xcb, 0xf8, 0x3, 0xcd, 0x61, 0x1, 0x29, 0x50, 0xf7, 0x79, 0xef, 0x2, 0x95, 0x44, 0x28, 0x72, 0xfb, 0xef, 0xf7, 0xc5, 0xb2, 0x98, 0x81, 0x1b, 0x9f, 0x82, 0xef, 0xb6, 0xb5, 0xc, 0x3c, 0x38, 0xad, 0xf0, 0xbc, 0xa3, 0x10, 0xca, 0x20, 0xc6, 0xc0, 0x82, 0xec, 0x48, 0x30, 0x74, 0xff, 0xef, 0xfd, 0xcf, 0xf3, 0x81, 0xd5, 0x54, 0x36, 0x1d, 0xa0, 0x6e, 0x46, 0xc, 0x6f, 0xba, 0xdf, 0x73, 0x3f, 0xaa, 0x9e, 0xc2, 0xa4, 0xc1, 0x20, 0xcc, 0xc0, 0x8a, 0x3d, 0xa0, 0x54, 0x18, 0xa4, 0x80, 0x3a, 0x99, 0x18, 0xe8, 0x9, 0x0, 0xf1, 0x9, 0x63, 0x9b, 0x53, 0x7f, 0x6d, 0x9b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vslider_grabber_hl_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0xc3, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x17, 0x2a, 0x29, 0x3a, 0x69, 0x69, 0x5b, 0xa6, 0xa5, 0x61, 0xb3, 0xbc, 0x63, 0xb7, 0xc8, 0x65, 0xbb, 0xca, 0x60, 0xaf, 0xb1, 0x48, 0x83, 0x83, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0xf, 0xf, 0x55, 0x9b, 0x9a, 0x60, 0xb2, 0xbd, 0x5e, 0xb1, 0xcd, 0x61, 0xb3, 0xc2, 0x0, 0x0, 0x0, 0x27, 0x48, 0x47, 0x62, 0xb4, 0xbd, 0x51, 0x93, 0x92, 0x68, 0xc0, 0xcf, 0x0, 0x0, 0x0, 0x56, 0x9d, 0x9c, 0x68, 0xc1, 0xcf, 0x2d, 0x52, 0x52, 0x63, 0xb7, 0xbf, 0x52, 0x96, 0x95, 0x62, 0xb3, 0xbf, 0x5e, 0xb0, 0xcd, 0x0, 0x0, 0x0, 0x3, 0x5, 0x5, 0x36, 0x63, 0x63, 0x63, 0xb4, 0xb6, 0x60, 0xb1, 0xbc, 0x63, 0xb7, 0xc7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x55, 0xa3, 0xc8, 0x4f, 0x98, 0xc4, 0x4b, 0x93, 0xc2, 0x4c, 0x94, 0xc2, 0x54, 0xa2, 0xc8, 0x5a, 0xab, 0xcb, 0x4e, 0x97, 0xc4, 0x49, 0x8f, 0xc0, 0x47, 0x8c, 0xbf, 0x48, 0x8e, 0xc0, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0x5a, 0xac, 0xcc, 0x53, 0x9f, 0xc7, 0x4d, 0x96, 0xc3, 0x4b, 0x92, 0xc2, 0xff, 0xff, 0xff, 0x76, 0xbd, 0x27, 0x7a, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x0, 0x88, 0x5, 0x1d, 0x48, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe1, 0x1, 0x12, 0x1, 0x36, 0x11, 0x34, 0xd2, 0xf, 0x93, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x48, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0xa0, 0x12, 0x10, 0x14, 0xe0, 0xe7, 0xe3, 0x45, 0xe2, 0x4b, 0x9a, 0x18, 0x1b, 0x19, 0x1a, 0x48, 0x88, 0x8b, 0xc1, 0xe4, 0x4d, 0x2c, 0x2d, 0x80, 0xc0, 0xdc, 0xcc, 0x54, 0x6, 0x22, 0x20, 0x60, 0x6c, 0x1, 0x1, 0xe6, 0x56, 0x72, 0x68, 0x2, 0xd6, 0x8a, 0xa8, 0x5a, 0x6c, 0x94, 0x11, 0x86, 0xda, 0xdb, 0xd9, 0xaa, 0xa9, 0xaa, 0x20, 0x59, 0xab, 0xa3, 0xad, 0xc5, 0x40, 0x3d, 0x0, 0x0, 0xbf, 0x8e, 0xc, 0xed, 0xed, 0xc7, 0x67, 0x72, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x6c, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x5b, 0xa6, 0xa5, 0x61, 0xb3, 0xbc, 0x63, 0xb7, 0xc8, 0x65, 0xbb, 0xca, 0x60, 0xaf, 0xb1, 0x55, 0x9b, 0x9a, 0x60, 0xb2, 0xbd, 0x5e, 0xb1, 0xcd, 0x61, 0xb3, 0xc2, 0x62, 0xb4, 0xbd, 0x68, 0xc0, 0xcf, 0x68, 0xc1, 0xcf, 0x63, 0xb7, 0xbf, 0x52, 0x96, 0x95, 0x62, 0xb3, 0xbf, 0x5e, 0xb0, 0xcd, 0x63, 0xb4, 0xb6, 0x60, 0xb1, 0xbc, 0x63, 0xb7, 0xc7, 0x55, 0xa3, 0xc8, 0x4f, 0x98, 0xc4, 0x4b, 0x93, 0xc2, 0x4c, 0x94, 0xc2, 0x54, 0xa2, 0xc8, 0x5a, 0xab, 0xcb, 0x4e, 0x97, 0xc4, 0x49, 0x8f, 0xc0, 0x47, 0x8c, 0xbf, 0x48, 0x8e, 0xc0, 0x52, 0x9e, 0xc6, 0x51, 0x9d, 0xc6, 0x5a, 0xac, 0xcc, 0x53, 0x9f, 0xc7, 0x4d, 0x96, 0xc3, 0x4b, 0x92, 0xc2, 0x7f, 0xcb, 0x5d, 0x16, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x47, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x16, 0x60, 0x65, 0x61, 0x66, 0x62, 0x44, 0xe2, 0x73, 0x4a, 0x88, 0x8b, 0x89, 0x8a, 0x70, 0xb0, 0xb3, 0xc1, 0xe4, 0x25, 0x64, 0x65, 0x80, 0x40, 0x5a, 0x4a, 0x92, 0xb, 0x22, 0xc0, 0x22, 0x2e, 0x3, 0x1, 0xd2, 0x72, 0xdc, 0x68, 0x2, 0xf2, 0x3c, 0xa8, 0x5a, 0x14, 0x78, 0x11, 0x86, 0x2a, 0x2b, 0x29, 0xa, 0xf0, 0xf3, 0x21, 0x59, 0x2b, 0x2c, 0x24, 0xc8, 0x40, 0x3d, 0x0, 0x0, 0x19, 0x8b, 0x5, 0xfc, 0x96, 0x5c, 0x15, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vslider_tick_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x4, 0x3, 0x0, 0x0, 0x0, 0x75, 0x9a, 0xa2, 0xdf, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x1e, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x81, 0xa2, 0xad, 0x8c, 0xac, 0xb8, 0x38, 0x55, 0x5f, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0xff, 0xff, 0xff, 0xe1, 0x56, 0x59, 0xc8, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x79, 0x79, 0x31, 0x1c, 0x18, 0xed, 0xfe, 0x2b, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x9, 0xf1, 0xd9, 0xa5, 0xec, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1d, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x80, 0x1, 0xd7, 0x44, 0x5, 0x6, 0x6, 0xe6, 0x92, 0x30, 0x86, 0xf2, 0x62, 0x3, 0x20, 0xa3, 0xbd, 0x1c, 0x2e, 0x3, 0x0, 0x3f, 0xce, 0x3, 0xaf, 0xf9, 0x94, 0x50, 0x96, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x4, 0x4, 0x3, 0x0, 0x0, 0x0, 0x75, 0x9a, 0xa2, 0xdf, 0x0, 0x0, 0x0, 0x1b, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x81, 0xa2, 0xad, 0x8c, 0xac, 0xb8, 0x38, 0x55, 0x5f, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x98, 0x98, 0x98, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x7c, 0xda, 0x48, 0x6d, 0x0, 0x0, 0x0, 0x9, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x79, 0x79, 0x79, 0x31, 0x1c, 0x18, 0xed, 0xfe, 0x2b, 0x0, 0x0, 0x0, 0x1c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x80, 0x3, 0xd7, 0x44, 0x5, 0x6, 0x6, 0xe6, 0x92, 0x30, 0x86, 0xf2, 0x62, 0x3, 0x20, 0xa3, 0xbd, 0x1c, 0x2e, 0x3, 0x0, 0x3f, 0xce, 0x3, 0xaf, 0xed, 0xed, 0x7c, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vsplit_bg_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0x1, 0x62, 0x4b, 0x47, 0x44, 0x1, 0xff, 0x2, 0x2d, 0xde, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0xb, 0x49, 0x44, 0x41, 0x54, 0x8, 0xd7, 0x63, 0x60, 0x40, 0x5, 0x0, 0x0, 0x10, 0x0, 0x1, 0xa1, 0xc5, 0x21, 0xc1, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x1, 0x3, 0x0, 0x0, 0x0, 0xfe, 0xc1, 0x2c, 0xc8, 0x0, 0x0, 0x0, 0x6, 0x50, 0x4c, 0x54, 0x45, 0x27, 0x27, 0x29, 0xff, 0xff, 0xff, 0x11, 0xab, 0xb9, 0xf3, 0x0, 0x0, 0x0, 0xa, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x3, 0x0, 0x0, 0x10, 0x0, 0x1, 0xb3, 0xac, 0xe2, 0xd0, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char vsplitter_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x9, 0xa6, 0x3, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x0, 0x0, 0x7a, 0x26, 0x0, 0x0, 0x80, 0x84, 0x0, 0x0, 0xfa, 0x0, 0x0, 0x0, 0x80, 0xe8, 0x0, 0x0, 0x75, 0x30, 0x0, 0x0, 0xea, 0x60, 0x0, 0x0, 0x3a, 0x98, 0x0, 0x0, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x6, 0x16, 0x12, 0x2b, 0x5, 0x39, 0x1a, 0x32, 0x39, 0x0, 0x0, 0x0, 0x1f, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0xa0, 0x10, 0x30, 0x33, 0x2c, 0x10, 0x3d, 0x47, 0x9, 0x66, 0x66, 0x10, 0xbd, 0xf6, 0x98, 0x22, 0x3c, 0xe0, 0x60, 0x18, 0x84, 0x1, 0x0, 0x59, 0x34, 0x6a, 0x2d, 0x64, 0xeb, 0x72, 0x24, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xc9, 0xad, 0xc8, 0x52, 0x0, 0x0, 0x0, 0x25, 0x74, 0x45, 0x58, 0x74, 0x64, 0x61, 0x74, 0x65, 0x3a, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0, 0x32, 0x30, 0x31, 0x36, 0x2d, 0x30, 0x36, 0x2d, 0x32, 0x32, 0x54, 0x32, 0x30, 0x3a, 0x33, 0x39, 0x3a, 0x32, 0x36, 0x2b, 0x30, 0x32, 0x3a, 0x30, 0x30, 0xb8, 0xf0, 0x70, 0xee, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x6c, 0x9, 0xa6, 0x3, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x76, 0x93, 0xcd, 0x38, 0x0, 0x0, 0x0, 0x18, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xa0, 0x1c, 0x2c, 0x48, 0xa5, 0xc, 0x33, 0xa4, 0x5a, 0x53, 0x86, 0x29, 0x7, 0xa3, 0x61, 0x0, 0x0, 0x18, 0x61, 0x34, 0xa1, 0xba, 0xa4, 0x4d, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static const unsigned char window_resizer_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x6, 0x0, 0x0, 0x0, 0x1f, 0xf3, 0xff, 0x61, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x7, 0x74, 0x49, 0x4d, 0x45, 0x7, 0xe0, 0x8, 0x19, 0x11, 0x33, 0x13, 0xaa, 0xc0, 0xf, 0x5f, 0x0, 0x0, 0x0, 0x19, 0x74, 0x45, 0x58, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x0, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x57, 0x81, 0xe, 0x17, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x38, 0xcb, 0x63, 0x60, 0x18, 0x5, 0x24, 0x81, 0x17, 0x2f, 0x5e, 0xf4, 0xa3, 0x8b, 0x31, 0x91, 0xa2, 0xb9, 0xb9, 0xb9, 0x99, 0x7c, 0x9b, 0xb3, 0xb3, 0xb3, 0xfb, 0x87, 0x81, 0x66, 0x6c, 0x81, 0x48, 0x92, 0x66, 0xa2, 0x5c, 0x43, 0x91, 0xe6, 0x11, 0xa, 0x0, 0x73, 0x5b, 0x34, 0x19, 0x10, 0xa0, 0xb6, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x1e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x18, 0xbc, 0xe0, 0x45, 0x3f, 0x1, 0xe9, 0xec, 0xfe, 0x81, 0x94, 0x86, 0xb1, 0x70, 0x48, 0x23, 0x58, 0x84, 0xa4, 0x7, 0x15, 0x0, 0x0, 0xed, 0x9f, 0x18, 0xe8, 0xcd, 0x91, 0xd8, 0xe, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; // shaders block diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index df5bbe9e6c..dc29102492 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -694,6 +694,8 @@ void SpatialMaterial::_update_shader() { } code += "\t\tbase_uv=ofs;\n"; + code += "\t\tif(base_uv.x > 1.0 || base_uv.y > 1.0 || base_uv.x < 0.0 || base_uv.y < 0.0)\n"; + code += "\t\t\tdiscard;\n"; if (features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) { code += "\t\tbase_uv2-=ofs;\n"; } @@ -2106,10 +2108,10 @@ void SpatialMaterial::_bind_methods() { SpatialMaterial::SpatialMaterial() : element(this) { - //initialize to right values + // Initialize to the same values as the shader set_albedo(Color(1.0, 1.0, 1.0, 1.0)); set_specular(0.5); - set_roughness(0.0); + set_roughness(1.0); set_metallic(0.0); set_emission(Color(0, 0, 0)); set_emission_energy(1.0); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 446b2b0e68..07783d5f4a 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -395,7 +395,15 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map nd.name = _nm_get_string(p_node->get_name(), name_map); nd.instance = -1; //not instanced by default - nd.index = p_node->get_index(); + + //really convoluted condition, but it basically checks that index is only saved when part of an inherited scene OR the node parent is from the edited scene + if (p_owner->get_scene_inherited_state().is_null() && (p_node == p_owner || (p_node->get_owner() == p_owner && (p_node->get_parent() == p_owner || p_node->get_parent()->get_owner() == p_owner)))) { + //do not save index, because it belongs to saved scene and scene is not inherited + nd.index = -1; + } else { + //part of an inherited scene, or parent is from an instanced scene + nd.index = p_node->get_index(); + } // if this node is part of an instanced scene or sub-instanced scene // we need to get the corresponding instance states. diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp index de3cfd1371..dc5ca1aef6 100644 --- a/scene/resources/physics_material.cpp +++ b/scene/resources/physics_material.cpp @@ -29,66 +29,48 @@ /*************************************************************************/ #include "physics_material.h" -bool PhysicsMaterial::_set(const StringName &p_name, const Variant &p_value) { - if (p_name == "bounce") { - set_bounce(p_value); - } else if (p_name == "bounce_combine_mode") { - set_bounce_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value))); - } else if (p_name == "friction") { - set_friction(p_value); - } else if (p_name == "friction_combine_mode") { - set_friction_combine_mode(static_cast<PhysicsServer::CombineMode>(int(p_value))); - } else { - return false; - } +void PhysicsMaterial::_bind_methods() { - emit_changed(); - return true; -} + ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicsMaterial::set_friction); + ClassDB::bind_method(D_METHOD("get_friction"), &PhysicsMaterial::get_friction); -bool PhysicsMaterial::_get(const StringName &p_name, Variant &r_ret) const { - if (p_name == "bounce") { - r_ret = bounce; - } else if (p_name == "bounce_combine_mode") { - r_ret = int(bounce_combine_mode); - } else if (p_name == "friction") { - r_ret = friction; - } else if (p_name == "friction_combine_mode") { - r_ret = int(friction_combine_mode); - } else { - return false; - } + ClassDB::bind_method(D_METHOD("set_rough", "rough"), &PhysicsMaterial::set_rough); + ClassDB::bind_method(D_METHOD("is_rough"), &PhysicsMaterial::is_rough); - return true; -} + ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicsMaterial::set_bounce); + ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicsMaterial::get_bounce); -void PhysicsMaterial::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::REAL, "bounce")); - p_list->push_back(PropertyInfo(Variant::INT, "bounce_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average")); - p_list->push_back(PropertyInfo(Variant::REAL, "friction")); - p_list->push_back(PropertyInfo(Variant::INT, "friction_combine_mode", PROPERTY_HINT_ENUM, "Max,Min,Multiply,Average")); -} + ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent); + ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent); -void PhysicsMaterial::_bind_methods() {} + ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction"), "set_friction", "get_friction"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce"), "set_bounce", "get_bounce"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent"); +} -void PhysicsMaterial::set_bounce(real_t p_val) { - bounce = p_val; +void PhysicsMaterial::set_friction(real_t p_val) { + friction = p_val; + emit_changed(); } -void PhysicsMaterial::set_bounce_combine_mode(PhysicsServer::CombineMode p_val) { - bounce_combine_mode = p_val; +void PhysicsMaterial::set_rough(bool p_val) { + rough = p_val; + emit_changed(); } -void PhysicsMaterial::set_friction(real_t p_val) { - friction = p_val; +void PhysicsMaterial::set_bounce(real_t p_val) { + bounce = p_val; + emit_changed(); } -void PhysicsMaterial::set_friction_combine_mode(PhysicsServer::CombineMode p_val) { - friction_combine_mode = p_val; +void PhysicsMaterial::set_absorbent(bool p_val) { + absorbent = p_val; + emit_changed(); } PhysicsMaterial::PhysicsMaterial() : + friction(1), + rough(false), bounce(0), - bounce_combine_mode(PhysicsServer::COMBINE_MODE_MAX), - friction(0), - friction_combine_mode(PhysicsServer::COMBINE_MODE_MULTIPLY) {} + absorbent(false) {} diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h index a6cb8c288e..dfe48d94cf 100644 --- a/scene/resources/physics_material.h +++ b/scene/resources/physics_material.h @@ -39,30 +39,34 @@ class PhysicsMaterial : public Resource { OBJ_SAVE_TYPE(PhysicsMaterial); RES_BASE_EXTENSION("PhyMat"); - real_t bounce; - PhysicsServer::CombineMode bounce_combine_mode; real_t friction; - PhysicsServer::CombineMode friction_combine_mode; + bool rough; + real_t bounce; + bool absorbent; protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - static void _bind_methods(); public: + void set_friction(real_t p_val); + _FORCE_INLINE_ real_t get_friction() const { return friction; } + + void set_rough(bool p_val); + _FORCE_INLINE_ bool is_rough() const { return rough; } + + _FORCE_INLINE_ real_t computed_friction() const { + return rough ? -friction : friction; + } + void set_bounce(real_t p_val); _FORCE_INLINE_ real_t get_bounce() const { return bounce; } - void set_bounce_combine_mode(PhysicsServer::CombineMode p_val); - _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } - - void set_friction(real_t p_val); - _FORCE_INLINE_ real_t get_friction() const { return friction; } + void set_absorbent(bool p_val); + _FORCE_INLINE_ bool is_absorbent() const { return absorbent; } - void set_friction_combine_mode(PhysicsServer::CombineMode p_val); - _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } + _FORCE_INLINE_ real_t computed_bounce() const { + return absorbent ? -bounce : bounce; + } PhysicsMaterial(); }; diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp index f2d5cb3516..4176aed4d8 100644 --- a/scene/resources/sky_box.cpp +++ b/scene/resources/sky_box.cpp @@ -405,7 +405,7 @@ void ProceduralSky::_update_sky() { } else { Ref<Image> image = _generate_sky(); - VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); + VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); VS::get_singleton()->texture_set_data(texture, image); _radiance_changed(); } @@ -422,7 +422,7 @@ void ProceduralSky::_queue_update() { void ProceduralSky::_thread_done(const Ref<Image> &p_image) { - VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), Image::FORMAT_RGBE9995, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); + VS::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, Image::FORMAT_RGBE9995, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER | VS::TEXTURE_FLAG_REPEAT); VS::get_singleton()->texture_set_data(texture, p_image); _radiance_changed(); Thread::wait_to_finish(sky_thread); @@ -532,14 +532,14 @@ ProceduralSky::ProceduralSky() { texture = VS::get_singleton()->texture_create(); update_queued = false; - sky_top_color = Color::hex(0x0c74f9ff); - sky_horizon_color = Color::hex(0x8ed2e8ff); - sky_curve = 0.25; + sky_top_color = Color::hex(0xa5d6f1ff); + sky_horizon_color = Color::hex(0xd6eafaff); + sky_curve = 0.09; sky_energy = 1; - ground_bottom_color = Color::hex(0x1a2530ff); - ground_horizon_color = Color::hex(0x7bc9f3ff); - ground_curve = 0.01; + ground_bottom_color = Color::hex(0x282f36ff); + ground_horizon_color = Color::hex(0x6c655fff); + ground_curve = 0.02; ground_energy = 1; sun_color = Color(1, 1, 1); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index c8d12b88fc..2f663431de 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -124,7 +124,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) { Size2 s = p_value; w = s.width; h = s.height; - VisualServer::get_singleton()->texture_set_size_override(texture, w, h); + VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0); } else if (p_name == "_data") { _set_data(p_value); } else @@ -151,13 +151,6 @@ bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const { void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const { - PropertyHint img_hint = PROPERTY_HINT_NONE; - if (storage == STORAGE_COMPRESS_LOSSY) { - img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY; - } else if (storage == STORAGE_COMPRESS_LOSSLESS) { - img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS; - } - p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat")); p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "")); @@ -183,7 +176,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) { void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) { flags = p_flags; - VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, p_format, p_flags); + VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, 0, p_format, VS::TEXTURE_TYPE_2D, p_flags); format = p_format; w = p_width; h = p_height; @@ -196,7 +189,7 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image, uint32_t p_flags h = p_image->get_height(); format = p_image->get_format(); - VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), p_flags); + VisualServer::get_singleton()->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags); VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); } @@ -221,9 +214,10 @@ Image::Format ImageTexture::get_format() const { return format; } - +#ifndef DISABLE_DEPRECATED Error ImageTexture::load(const String &p_path) { + WARN_DEPRECATED Ref<Image> img; img.instance(); Error err = img->load(p_path); @@ -232,7 +226,7 @@ Error ImageTexture::load(const String &p_path) { } return err; } - +#endif void ImageTexture::set_data(const Ref<Image> &p_image) { ERR_FAIL_COND(p_image.is_null()); @@ -301,7 +295,7 @@ void ImageTexture::set_size_override(const Size2 &p_size) { w = s.x; if (s.y != 0) h = s.y; - VisualServer::get_singleton()->texture_set_size_override(texture, w, h); + VisualServer::get_singleton()->texture_set_size_override(texture, w, h, 0); } void ImageTexture::set_path(const String &p_path, bool p_take_over) { @@ -352,7 +346,9 @@ void ImageTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("create", "width", "height", "format", "flags"), &ImageTexture::create, DEFVAL(FLAGS_DEFAULT)); ClassDB::bind_method(D_METHOD("create_from_image", "image", "flags"), &ImageTexture::create_from_image, DEFVAL(FLAGS_DEFAULT)); ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("load", "path"), &ImageTexture::load); +#endif ClassDB::bind_method(D_METHOD("set_data", "image"), &ImageTexture::set_data); ClassDB::bind_method(D_METHOD("set_storage", "mode"), &ImageTexture::set_storage); ClassDB::bind_method(D_METHOD("get_storage"), &ImageTexture::get_storage); @@ -592,7 +588,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &fla int sh = th; int mipmaps = Image::get_image_required_mipmaps(tw, th, format); - int total_size = Image::get_image_data_size(tw, th, format, mipmaps); + int total_size = Image::get_image_data_size(tw, th, format, true); int idx = 0; int ofs = 0; @@ -648,7 +644,7 @@ Error StreamTexture::load(const String &p_path) { if (err) return err; - VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), image->get_format(), lflags); + VS::get_singleton()->texture_allocate(texture, image->get_width(), image->get_height(), 0, image->get_format(), VS::TEXTURE_TYPE_2D, lflags); VS::get_singleton()->texture_set_data(texture, image); w = lw; @@ -1155,7 +1151,6 @@ void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile Size2 scale = p_rect.size / size; - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); for (int i = 0; i < pieces.size(); i++) { // TODO @@ -1170,7 +1165,6 @@ void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons Size2 scale = p_rect.size / p_src_rect.size; - RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID(); for (int i = 0; i < pieces.size(); i++) { // TODO @@ -1195,7 +1189,7 @@ void CubeMap::set_flags(uint32_t p_flags) { flags = p_flags; if (_is_valid()) - VS::get_singleton()->texture_set_flags(cubemap, flags | VS::TEXTURE_FLAG_CUBEMAP); + VS::get_singleton()->texture_set_flags(cubemap, flags); } uint32_t CubeMap::get_flags() const { @@ -1211,7 +1205,7 @@ void CubeMap::set_side(Side p_side, const Ref<Image> &p_image) { format = p_image->get_format(); w = p_image->get_width(); h = p_image->get_height(); - VS::get_singleton()->texture_allocate(cubemap, w, h, p_image->get_format(), flags | VS::TEXTURE_FLAG_CUBEMAP); + VS::get_singleton()->texture_allocate(cubemap, w, h, 0, p_image->get_format(), VS::TEXTURE_TYPE_CUBEMAP, flags); } VS::get_singleton()->texture_set_data(cubemap, p_image, VS::CubeMapSide(p_side)); @@ -1322,13 +1316,6 @@ bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const { void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const { - PropertyHint img_hint = PROPERTY_HINT_NONE; - if (storage == STORAGE_COMPRESS_LOSSY) { - img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY; - } else if (storage == STORAGE_COMPRESS_LOSSLESS) { - img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS; - } - p_list->push_back(PropertyInfo(Variant::OBJECT, "side/left", PROPERTY_HINT_RESOURCE_TYPE, "Image")); p_list->push_back(PropertyInfo(Variant::OBJECT, "side/right", PROPERTY_HINT_RESOURCE_TYPE, "Image")); p_list->push_back(PropertyInfo(Variant::OBJECT, "side/bottom", PROPERTY_HINT_RESOURCE_TYPE, "Image")); @@ -1474,7 +1461,7 @@ void CurveTexture::_update() { Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data)); - VS::get_singleton()->texture_allocate(_texture, _width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER); + VS::get_singleton()->texture_allocate(_texture, _width, 1, 0, Image::FORMAT_RF, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER); VS::get_singleton()->texture_set_data(_texture, image); emit_changed(); @@ -1583,7 +1570,7 @@ void GradientTexture::_update() { Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data)); - VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RGBA8, VS::TEXTURE_FLAG_FILTER); + VS::get_singleton()->texture_allocate(texture, width, 1, 0, Image::FORMAT_RGBA8, VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER); VS::get_singleton()->texture_set_data(texture, image); emit_changed(); @@ -1876,3 +1863,327 @@ AnimatedTexture::AnimatedTexture() { AnimatedTexture::~AnimatedTexture() { VS::get_singleton()->free(proxy); } +/////////////////////////////// + +void TextureLayered::set_flags(uint32_t p_flags) { + flags = p_flags; + + if (texture.is_valid()) { + VS::get_singleton()->texture_set_flags(texture, flags); + } +} + +uint32_t TextureLayered::get_flags() const { + return flags; +} + +Image::Format TextureLayered::get_format() const { + return format; +} + +uint32_t TextureLayered::get_width() const { + return width; +} + +uint32_t TextureLayered::get_height() const { + return height; +} + +uint32_t TextureLayered::get_depth() const { + return depth; +} + +void TextureLayered::_set_data(const Dictionary &p_data) { + ERR_FAIL_COND(!p_data.has("width")); + ERR_FAIL_COND(!p_data.has("height")); + ERR_FAIL_COND(!p_data.has("depth")); + ERR_FAIL_COND(!p_data.has("format")); + ERR_FAIL_COND(!p_data.has("flags")); + ERR_FAIL_COND(!p_data.has("layers")); + int w = p_data["width"]; + int h = p_data["height"]; + int d = p_data["depth"]; + Image::Format format = Image::Format(int(p_data["format"])); + int flags = p_data["flags"]; + Array layers = p_data["layers"]; + ERR_FAIL_COND(layers.size() != d); + + create(w, h, d, format, flags); + + for (int i = 0; i < layers.size(); i++) { + Ref<Image> img = layers[i]; + ERR_CONTINUE(!img.is_valid()); + ERR_CONTINUE(img->get_format() != format); + ERR_CONTINUE(img->get_width() != w); + ERR_CONTINUE(img->get_height() != h); + set_layer_data(img, i); + } +} + +Dictionary TextureLayered::_get_data() const { + Dictionary d; + d["width"] = width; + d["height"] = height; + d["depth"] = depth; + d["flags"] = flags; + d["format"] = format; + + Array layers; + for (int i = 0; i < depth; i++) { + layers.push_back(get_layer_data(i)); + } + d["layers"] = layers; + return d; +} + +void TextureLayered::create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags) { + VS::get_singleton()->texture_allocate(texture, p_width, p_height, p_depth, p_format, is_3d ? VS::TEXTURE_TYPE_3D : VS::TEXTURE_TYPE_2D_ARRAY, p_flags); + + width = p_width; + height = p_height; + depth = p_depth; + + flags = p_flags; +} + +void TextureLayered::set_layer_data(const Ref<Image> &p_image, int p_layer) { + ERR_FAIL_COND(!texture.is_valid()); + VS::get_singleton()->texture_set_data(texture, p_image, p_layer); +} + +Ref<Image> TextureLayered::get_layer_data(int p_layer) const { + + ERR_FAIL_COND_V(!texture.is_valid(), Ref<Image>()); + return VS::get_singleton()->texture_get_data(texture, p_layer); +} + +void TextureLayered::set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap) { + ERR_FAIL_COND(!texture.is_valid()); + VS::get_singleton()->texture_set_data_partial(texture, p_image, 0, 0, p_image->get_width(), p_image->get_height(), p_x_ofs, p_y_ofs, p_mipmap, p_z); +} + +RID TextureLayered::get_rid() const { + return texture; +} + +void TextureLayered::set_path(const String &p_path, bool p_take_over) { + if (texture.is_valid()) { + VS::get_singleton()->texture_set_path(texture, p_path); + } + + Resource::set_path(p_path, p_take_over); +} + +void TextureLayered::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_flags", "flags"), &TextureLayered::set_flags); + ClassDB::bind_method(D_METHOD("get_flags"), &TextureLayered::get_flags); + + ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format); + + ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height); + ClassDB::bind_method(D_METHOD("get_depth"), &TextureLayered::get_depth); + + ClassDB::bind_method(D_METHOD("create", "width", "height", "depth", "format", "flags"), &TextureLayered::create, DEFVAL(FLAGS_DEFAULT)); + ClassDB::bind_method(D_METHOD("set_layer_data", "image", "layer"), &TextureLayered::set_layer_data); + ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::set_layer_data); + ClassDB::bind_method(D_METHOD("set_data_partial", "image", "x_offset", "y_offset", "layer", "mipmap"), &TextureLayered::set_data_partial, DEFVAL(0)); + + ClassDB::bind_method(D_METHOD("_set_data", "data"), &TextureLayered::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &TextureLayered::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); + + BIND_ENUM_CONSTANT(FLAG_MIPMAPS); + BIND_ENUM_CONSTANT(FLAG_REPEAT); + BIND_ENUM_CONSTANT(FLAG_FILTER); + BIND_ENUM_CONSTANT(FLAGS_DEFAULT); +} + +TextureLayered::TextureLayered(bool p_3d) { + is_3d = p_3d; + format = Image::FORMAT_MAX; + flags = FLAGS_DEFAULT; + + width = 0; + height = 0; + depth = 0; + + texture = VS::get_singleton()->texture_create(); +} + +TextureLayered::~TextureLayered() { + if (texture.is_valid()) { + VS::get_singleton()->free(texture); + } +} + +RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error) { + + if (r_error) { + *r_error = ERR_CANT_OPEN; + } + + Ref<TextureLayered> lt; + Ref<Texture3D> tex3d; + Ref<TextureArray> texarr; + + if (p_path.ends_with("tex3d")) { + tex3d.instance(); + lt = tex3d; + } else if (p_path.ends_with("texarr")) { + texarr.instance(); + lt = texarr; + } else { + ERR_EXPLAIN("Unrecognized layered texture extension"); + ERR_FAIL_V(RES()); + } + + FileAccess *f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V(!f, RES()); + + uint8_t header[5] = { 0, 0, 0, 0, 0 }; + f->get_buffer(header, 4); + + if (header[0] == 'G' && header[1] == 'D' && header[2] == '3' && header[3] == 'T') { + if (tex3d.is_null()) { + memdelete(f); + ERR_FAIL_COND_V(tex3d.is_null(), RES()) + } + } else if (header[0] == 'G' && header[1] == 'D' && header[2] == 'A' && header[3] == 'T') { + if (texarr.is_null()) { + memdelete(f); + ERR_FAIL_COND_V(texarr.is_null(), RES()) + } + } else { + + ERR_EXPLAIN("Unrecognized layered texture file format: " + String((const char *)header)); + ERR_FAIL_V(RES()); + } + + int tw = f->get_32(); + int th = f->get_32(); + int td = f->get_32(); + int flags = f->get_32(); //texture flags! + Image::Format format = Image::Format(f->get_32()); + uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed + + lt->create(tw, th, td, format, flags); + + for (int layer = 0; layer < td; layer++) { + + Ref<Image> image; + image.instance(); + + if (compression == COMPRESSION_LOSSLESS) { + //look for a PNG file inside + + int mipmaps = f->get_32(); + Vector<Ref<Image> > mipmap_images; + + for (int i = 0; i < mipmaps; i++) { + uint32_t size = f->get_32(); + + PoolVector<uint8_t> pv; + pv.resize(size); + { + PoolVector<uint8_t>::Write w = pv.write(); + f->get_buffer(w.ptr(), size); + } + + Ref<Image> img = Image::lossless_unpacker(pv); + + if (img.is_null() || img->empty() || format != img->get_format()) { + if (r_error) { + *r_error = ERR_FILE_CORRUPT; + } + memdelete(f); + ERR_FAIL_V(RES()); + } + + mipmap_images.push_back(img); + } + + if (mipmap_images.size() == 1) { + + image = mipmap_images[0]; + + } else { + int total_size = Image::get_image_data_size(tw, th, format, true); + PoolVector<uint8_t> img_data; + img_data.resize(total_size); + + { + PoolVector<uint8_t>::Write w = img_data.write(); + + int ofs = 0; + for (int i = 0; i < mipmap_images.size(); i++) { + + PoolVector<uint8_t> id = mipmap_images[i]->get_data(); + int len = id.size(); + PoolVector<uint8_t>::Read r = id.read(); + copymem(&w[ofs], r.ptr(), len); + ofs += len; + } + } + + image->create(tw, th, true, format, img_data); + if (image->empty()) { + if (r_error) { + *r_error = ERR_FILE_CORRUPT; + } + memdelete(f); + ERR_FAIL_V(RES()); + } + } + + } else { + + //look for regular format + bool mipmaps = (flags & Texture::FLAG_MIPMAPS); + int total_size = Image::get_image_data_size(tw, th, format, mipmaps); + + PoolVector<uint8_t> img_data; + img_data.resize(total_size); + + { + PoolVector<uint8_t>::Write w = img_data.write(); + int bytes = f->get_buffer(w.ptr(), total_size); + if (bytes != total_size) { + if (r_error) { + *r_error = ERR_FILE_CORRUPT; + memdelete(f); + } + ERR_FAIL_V(RES()); + } + } + + image->create(tw, th, mipmaps, format, img_data); + } + + lt->set_layer_data(image, layer); + } + + if (r_error) + *r_error = OK; + + return lt; +} + +void ResourceFormatLoaderTextureLayered::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("tex3d"); + p_extensions->push_back("texarr"); +} +bool ResourceFormatLoaderTextureLayered::handles_type(const String &p_type) const { + return p_type == "Texture3D" || p_type == "TextureArray"; +} +String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_path) const { + + if (p_path.get_extension().to_lower() == "tex3d") + return "Texture3D"; + if (p_path.get_extension().to_lower() == "texarr") + return "TextureArray"; + return ""; +} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index c994bdad5f..c15efb6eaa 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -125,7 +125,9 @@ public: void set_flags(uint32_t p_flags); uint32_t get_flags() const; Image::Format get_format() const; +#ifndef DISABLE_DEPRECATED Error load(const String &p_path); +#endif void set_data(const Ref<Image> &p_image); Ref<Image> get_data() const; @@ -401,6 +403,88 @@ VARIANT_ENUM_CAST(CubeMap::Flags) VARIANT_ENUM_CAST(CubeMap::Side) VARIANT_ENUM_CAST(CubeMap::Storage) +class TextureLayered : public Resource { + + GDCLASS(TextureLayered, Resource) + +public: + enum Flags { + FLAG_MIPMAPS = VisualServer::TEXTURE_FLAG_MIPMAPS, + FLAG_REPEAT = VisualServer::TEXTURE_FLAG_REPEAT, + FLAG_FILTER = VisualServer::TEXTURE_FLAG_FILTER, + FLAG_CONVERT_TO_LINEAR = VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR, + FLAGS_DEFAULT = FLAG_FILTER, + }; + +private: + bool is_3d; + RID texture; + Image::Format format; + uint32_t flags; + + int width; + int height; + int depth; + + void _set_data(const Dictionary &p_data); + Dictionary _get_data() const; + +protected: + static void _bind_methods(); + +public: + void set_flags(uint32_t p_flags); + uint32_t get_flags() const; + + Image::Format get_format() const; + uint32_t get_width() const; + uint32_t get_height() const; + uint32_t get_depth() const; + + void create(uint32_t p_width, uint32_t p_height, uint32_t p_depth, Image::Format p_format, uint32_t p_flags = FLAGS_DEFAULT); + void set_layer_data(const Ref<Image> &p_image, int p_layer); + Ref<Image> get_layer_data(int p_layer) const; + void set_data_partial(const Ref<Image> &p_image, int p_x_ofs, int p_y_ofs, int p_z, int p_mipmap = 0); + + virtual RID get_rid() const; + virtual void set_path(const String &p_path, bool p_take_over = false); + + TextureLayered(bool p_3d = false); + ~TextureLayered(); +}; + +VARIANT_ENUM_CAST(TextureLayered::Flags) + +class Texture3D : public TextureLayered { + + GDCLASS(Texture3D, TextureLayered) +public: + Texture3D() : + TextureLayered(true) {} +}; + +class TextureArray : public TextureLayered { + + GDCLASS(TextureArray, TextureLayered) +public: + TextureArray() : + TextureLayered(false) {} +}; + +class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader { +public: + enum Compression { + COMPRESSION_LOSSLESS, + COMPRESSION_VRAM, + COMPRESSION_UNCOMPRESSED + }; + + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + class CurveTexture : public Texture { GDCLASS(CurveTexture, Texture) diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index dd50671fa0..3d2b6c36de 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -262,7 +262,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial")); p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate")); p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region")); - p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE")); + p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE,ATLAS_TILE")); if (tile_get_tile_mode(id) == AUTO_TILE) { p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); @@ -272,6 +272,12 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + } else if (tile_get_tile_mode(id) == ATLAS_TILE) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); } p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset")); p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D")); @@ -494,8 +500,21 @@ uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) { const Map<Vector2, uint16_t> &TileSet::autotile_get_bitmask_map(int p_id) { static Map<Vector2, uint16_t> dummy; + static Map<Vector2, uint16_t> dummy_atlas; ERR_FAIL_COND_V(!tile_map.has(p_id), dummy); - return tile_map[p_id].autotile_data.flags; + if (tile_get_tile_mode(p_id) == ATLAS_TILE) { + dummy_atlas = Map<Vector2, uint16_t>(); + Rect2 region = tile_get_region(p_id); + Size2 size = autotile_get_size(p_id); + float spacing = autotile_get_spacing(p_id); + for (int x = 0; x < (region.size.x / (size.x + spacing)); x++) { + for (int y = 0; y < (region.size.y / (size.y + spacing)); y++) { + dummy_atlas.insert(Vector2(x, y), 0); + } + } + return dummy_atlas; + } else + return tile_map[p_id].autotile_data.flags; } Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node, const Vector2 &p_tile_location) { @@ -976,7 +995,7 @@ void TileSet::_bind_methods() { BIND_ENUM_CONSTANT(SINGLE_TILE); BIND_ENUM_CONSTANT(AUTO_TILE); - BIND_ENUM_CONSTANT(ANIMATED_TILE); + BIND_ENUM_CONSTANT(ATLAS_TILE); } TileSet::TileSet() { diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index ec635ee5cc..40eee2700d 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -75,7 +75,7 @@ public: enum TileMode { SINGLE_TILE, AUTO_TILE, - ANIMATED_TILE + ATLAS_TILE }; struct AutotileData { diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 113f23f8f2..eef8aba0c4 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "audio_stream.h" +#include "os/os.h" ////////////////////////////// @@ -99,6 +100,119 @@ void AudioStream::_bind_methods() { //////////////////////////////// +Ref<AudioStreamPlayback> AudioStreamMicrophone::instance_playback() { + Ref<AudioStreamPlaybackMicrophone> playback; + playback.instance(); + + playbacks.insert(playback.ptr()); + + playback->microphone = Ref<AudioStreamMicrophone>((AudioStreamMicrophone *)this); + playback->active = false; + + return playback; +} + +String AudioStreamMicrophone::get_stream_name() const { + + //if (audio_stream.is_valid()) { + //return "Random: " + audio_stream->get_name(); + //} + return "Microphone"; +} + +float AudioStreamMicrophone::get_length() const { + return 0; +} + +void AudioStreamMicrophone::_bind_methods() { +} + +AudioStreamMicrophone::AudioStreamMicrophone() { +} + +void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) { + + AudioDriver::get_singleton()->lock(); + + Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer(); + unsigned int input_size = AudioDriver::get_singleton()->get_input_size(); + + // p_frames is multipled by two since an AudioFrame is stereo + if ((p_frames + MICROPHONE_PLAYBACK_DELAY * 2) > input_size) { + for (int i = 0; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0.0f, 0.0f); + } + input_ofs = 0; + } else { + for (int i = 0; i < p_frames; i++) { + if (input_size >= input_ofs) { + float l = (buf[input_ofs++] >> 16) / 32768.f; + if (input_ofs >= buf.size()) { + input_ofs = 0; + } + float r = (buf[input_ofs++] >> 16) / 32768.f; + if (input_ofs >= buf.size()) { + input_ofs = 0; + } + + p_buffer[i] = AudioFrame(l, r); + } else { + p_buffer[i] = AudioFrame(0.0f, 0.0f); + } + } + } + + AudioDriver::get_singleton()->unlock(); +} + +void AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { + AudioStreamPlaybackResampled::mix(p_buffer, p_rate_scale, p_frames); +} + +float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() { + return AudioDriver::get_singleton()->get_mix_rate(); +} + +void AudioStreamPlaybackMicrophone::start(float p_from_pos) { + input_ofs = 0; + + AudioDriver::get_singleton()->capture_start(); + + active = true; + _begin_resample(); +} + +void AudioStreamPlaybackMicrophone::stop() { + AudioDriver::get_singleton()->capture_stop(); + active = false; +} + +bool AudioStreamPlaybackMicrophone::is_playing() const { + return active; +} + +int AudioStreamPlaybackMicrophone::get_loop_count() const { + return 0; +} + +float AudioStreamPlaybackMicrophone::get_playback_position() const { + return 0; +} + +void AudioStreamPlaybackMicrophone::seek(float p_time) { + return; // Can't seek a microphone input +} + +AudioStreamPlaybackMicrophone::~AudioStreamPlaybackMicrophone() { + microphone->playbacks.erase(this); + stop(); +} + +AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() { +} + +//////////////////////////////// + void AudioStreamRandomPitch::set_audio_stream(const Ref<AudioStream> &p_audio_stream) { audio_stream = p_audio_stream; diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 3312ce1ff6..66e1b6ee2f 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -94,6 +94,63 @@ public: virtual float get_length() const = 0; //if supported, otherwise return 0 }; +// Microphone + +class AudioStreamPlaybackMicrophone; + +class AudioStreamMicrophone : public AudioStream { + + GDCLASS(AudioStreamMicrophone, AudioStream) + friend class AudioStreamPlaybackMicrophone; + + Set<AudioStreamPlaybackMicrophone *> playbacks; + +protected: + static void _bind_methods(); + +public: + virtual Ref<AudioStreamPlayback> instance_playback(); + virtual String get_stream_name() const; + + virtual float get_length() const; //if supported, otherwise return 0 + + AudioStreamMicrophone(); +}; + +class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled { + + GDCLASS(AudioStreamPlaybackMicrophone, AudioStreamPlayback) + friend class AudioStreamMicrophone; + + const int MICROPHONE_PLAYBACK_DELAY = 256; + + bool active; + unsigned int input_ofs; + + Ref<AudioStreamMicrophone> microphone; + +protected: + virtual void _mix_internal(AudioFrame *p_buffer, int p_frames); + virtual float get_stream_sampling_rate(); + +public: + virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); + + virtual void start(float p_from_pos = 0.0); + virtual void stop(); + virtual bool is_playing() const; + + virtual int get_loop_count() const; //times it looped + + virtual float get_playback_position() const; + virtual void seek(float p_time); + + ~AudioStreamPlaybackMicrophone(); + AudioStreamPlaybackMicrophone(); +}; + +// + class AudioStreamPlaybackRandomPitch; class AudioStreamRandomPitch : public AudioStream { diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 2eaa2ce8e7..f3934e5c01 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -33,6 +33,7 @@ #include "os/file_access.h" #include "os/os.h" #include "project_settings.h" +#include "scene/resources/audio_stream_sample.h" #include "servers/audio/audio_driver_dummy.h" #include "servers/audio/effects/audio_effect_compressor.h" #ifdef TOOLS_ENABLED @@ -79,6 +80,17 @@ double AudioDriver::get_mix_time() const { return total; } +void AudioDriver::input_buffer_write(int32_t sample) { + + input_buffer.write[input_position++] = sample; + if (input_position >= input_buffer.size()) { + input_position = 0; + } + if (input_size < input_buffer.size()) { + input_size++; + } +} + AudioDriver::SpeakerMode AudioDriver::get_speaker_mode_by_total_channels(int p_channels) const { switch (p_channels) { case 4: return SPEAKER_SURROUND_31; @@ -113,6 +125,14 @@ String AudioDriver::get_device() { return "Default"; } +Array AudioDriver::capture_get_device_list() { + Array list; + + list.push_back("Default"); + + return list; +} + AudioDriver::AudioDriver() { _last_mix_time = 0; @@ -123,14 +143,19 @@ AudioDriver::AudioDriver() { #endif } -AudioDriver *AudioDriverManager::drivers[MAX_DRIVERS]; -int AudioDriverManager::driver_count = 0; AudioDriverDummy AudioDriverManager::dummy_driver; +AudioDriver *AudioDriverManager::drivers[MAX_DRIVERS] = { + &AudioDriverManager::dummy_driver, +}; +int AudioDriverManager::driver_count = 1; void AudioDriverManager::add_driver(AudioDriver *p_driver) { ERR_FAIL_COND(driver_count >= MAX_DRIVERS); - drivers[driver_count++] = p_driver; + drivers[driver_count - 1] = p_driver; + + // Last driver is always our dummy driver + drivers[driver_count++] = &AudioDriverManager::dummy_driver; } int AudioDriverManager::get_driver_count() { @@ -163,14 +188,6 @@ void AudioDriverManager::initialize(int p_driver) { return; } } - - // Fallback to our dummy driver - if (dummy_driver.init() == OK) { - ERR_PRINT("AudioDriverManager: all drivers failed, falling back to dummy driver"); - dummy_driver.set_singleton(); - } else { - ERR_PRINT("AudioDriverManager: dummy driver failed to init()"); - } } AudioDriver *AudioDriverManager::get_driver(int p_driver) { @@ -1201,6 +1218,21 @@ void AudioServer::set_device(String device) { AudioDriver::get_singleton()->set_device(device); } +Array AudioServer::capture_get_device_list() { + + return AudioDriver::get_singleton()->capture_get_device_list(); +} + +String AudioServer::capture_get_device() { + + return AudioDriver::get_singleton()->capture_get_device(); +} + +void AudioServer::capture_set_device(const String &p_name) { + + AudioDriver::get_singleton()->capture_set_device(p_name); +} + void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_count", "amount"), &AudioServer::set_bus_count); @@ -1251,6 +1283,10 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device"), &AudioServer::get_device); ClassDB::bind_method(D_METHOD("set_device"), &AudioServer::set_device); + ClassDB::bind_method(D_METHOD("capture_get_device_list"), &AudioServer::capture_get_device_list); + ClassDB::bind_method(D_METHOD("capture_get_device"), &AudioServer::capture_get_device); + ClassDB::bind_method(D_METHOD("capture_set_device"), &AudioServer::capture_set_device); + ClassDB::bind_method(D_METHOD("set_bus_layout", "bus_layout"), &AudioServer::set_bus_layout); ClassDB::bind_method(D_METHOD("generate_bus_layout"), &AudioServer::generate_bus_layout); diff --git a/servers/audio_server.h b/servers/audio_server.h index 258fd1d9b0..2663a0f968 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -38,6 +38,8 @@ #include "variant.h" class AudioDriverDummy; +class AudioStream; +class AudioStreamSample; class AudioDriver { @@ -51,8 +53,13 @@ class AudioDriver { #endif protected: + Vector<int32_t> input_buffer; + unsigned int input_position; + unsigned int input_size; + void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true); void update_mix_time(int p_frames); + void input_buffer_write(int32_t sample); #ifdef DEBUG_ENABLED _FORCE_INLINE_ void start_counting_ticks() { prof_ticks = OS::get_singleton()->get_ticks_usec(); } @@ -91,11 +98,21 @@ public: virtual void unlock() = 0; virtual void finish() = 0; + virtual Error capture_start() { return FAILED; } + virtual Error capture_stop() { return FAILED; } + virtual void capture_set_device(const String &p_name) {} + virtual String capture_get_device() { return "Default"; } + virtual Array capture_get_device_list(); // TODO: convert this and get_device_list to PoolStringArray + virtual float get_latency() { return 0; } SpeakerMode get_speaker_mode_by_total_channels(int p_channels) const; int get_total_channels_by_speaker_mode(SpeakerMode) const; + Vector<int32_t> get_input_buffer() { return input_buffer; } + unsigned int get_input_position() { return input_position; } + unsigned int get_input_size() { return input_size; } + #ifdef DEBUG_ENABLED uint64_t get_profiling_time() const { return prof_time; } void reset_profiling_time() { prof_time = 0; } @@ -222,6 +239,18 @@ private: void _mix_step(); +#if 0 + struct AudioInBlock { + + Ref<AudioStreamSample> audio_stream; + int current_position; + bool loops; + }; + + Map<StringName, AudioInBlock *> audio_in_block_map; + Vector<AudioInBlock *> audio_in_blocks; +#endif + struct CallbackItem { AudioCallback callback; @@ -335,8 +364,11 @@ public: String get_device(); void set_device(String device); - float get_output_latency() { return output_latency; } + Array capture_get_device_list(); + String capture_get_device(); + void capture_set_device(const String &p_name); + float get_output_latency() { return output_latency; } AudioServer(); virtual ~AudioServer(); }; diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp index 5a41b621eb..0ce38e4486 100644 --- a/servers/physics/body_pair_sw.cpp +++ b/servers/physics/body_pair_sw.cpp @@ -212,41 +212,11 @@ bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Tran } real_t combine_bounce(BodySW *A, BodySW *B) { - const PhysicsServer::CombineMode cm = A->get_bounce_combine_mode(); - - switch (cm) { - case PhysicsServer::COMBINE_MODE_INHERIT: - if (B->get_bounce_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) - return combine_bounce(B, A); - // else use MAX [This is used when the two bodies doesn't use physical material] - case PhysicsServer::COMBINE_MODE_MAX: - return MAX(A->get_bounce(), B->get_bounce()); - case PhysicsServer::COMBINE_MODE_MIN: - return MIN(A->get_bounce(), B->get_bounce()); - case PhysicsServer::COMBINE_MODE_MULTIPLY: - return A->get_bounce() * B->get_bounce(); - default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: - return (A->get_bounce() + B->get_bounce()) / 2; - } + return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1); } real_t combine_friction(BodySW *A, BodySW *B) { - const PhysicsServer::CombineMode cm = A->get_friction_combine_mode(); - - switch (cm) { - case PhysicsServer::COMBINE_MODE_INHERIT: - if (B->get_friction_combine_mode() != PhysicsServer::COMBINE_MODE_INHERIT) - return combine_friction(B, A); - // else use Multiply [This is used when the two bodies doesn't use physical material] - case PhysicsServer::COMBINE_MODE_MULTIPLY: - return A->get_friction() * B->get_friction(); - case PhysicsServer::COMBINE_MODE_MAX: - return MAX(A->get_friction(), B->get_friction()); - case PhysicsServer::COMBINE_MODE_MIN: - return MIN(A->get_friction(), B->get_friction()); - default: // Is always PhysicsServer::COMBINE_MODE_AVERAGE: - return (A->get_friction() + B->get_friction()) / 2; - } + return ABS(MIN(A->get_friction(), B->get_friction())); } bool BodyPairSW::setup(real_t p_step) { diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp index 59f987fc17..cc9681193c 100644 --- a/servers/physics/body_sw.cpp +++ b/servers/physics/body_sw.cpp @@ -423,22 +423,6 @@ void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) { area_angular_damp += p_area->get_angular_damp(); } -void BodySW::set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode) { - if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { - bounce_combine_mode = p_mode; - } else { - friction_combine_mode = p_mode; - } -} - -PhysicsServer::CombineMode BodySW::get_combine_mode(PhysicsServer::BodyParameter p_param) const { - if (p_param == PhysicsServer::BODY_PARAM_BOUNCE) { - return bounce_combine_mode; - } else { - return friction_combine_mode; - } -} - void BodySW::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock) { if (lock) { locked_axis |= p_axis; diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index 5df270f679..9d7b147fd6 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -49,8 +49,6 @@ class BodySW : public CollisionObjectSW { real_t mass; real_t bounce; real_t friction; - PhysicsServer::CombineMode bounce_combine_mode; - PhysicsServer::CombineMode friction_combine_mode; real_t linear_damp; real_t angular_damp; @@ -304,12 +302,6 @@ public: _FORCE_INLINE_ Vector3 get_gravity() const { return gravity; } _FORCE_INLINE_ real_t get_bounce() const { return bounce; } - void set_combine_mode(PhysicsServer::BodyParameter p_param, PhysicsServer::CombineMode p_mode); - PhysicsServer::CombineMode get_combine_mode(PhysicsServer::BodyParameter p_param) const; - - _FORCE_INLINE_ PhysicsServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } - _FORCE_INLINE_ PhysicsServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } - void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool lock); bool is_axis_locked(PhysicsServer::BodyAxis p_axis) const; diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp index 8f2b147460..b059c20c95 100644 --- a/servers/physics/collision_solver_sat.cpp +++ b/servers/physics/collision_solver_sat.cpp @@ -560,6 +560,12 @@ static void _collision_sphere_capsule(const ShapeSW *p_a, const Transform &p_tra } template <bool withMargin> +static void _collision_sphere_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_sphere_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a); @@ -851,6 +857,12 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf } template <bool withMargin> +static void _collision_box_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_box_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a); @@ -1127,6 +1139,12 @@ static void _collision_capsule_capsule(const ShapeSW *p_a, const Transform &p_tr } template <bool withMargin> +static void _collision_capsule_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_capsule_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW *>(p_a); @@ -1247,6 +1265,24 @@ static void _collision_capsule_face(const ShapeSW *p_a, const Transform &p_trans } template <bool withMargin> +static void _collision_cylinder_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> +static void _collision_cylinder_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> +static void _collision_cylinder_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW *>(p_a); @@ -1475,59 +1511,81 @@ bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_tran ERR_FAIL_COND_V(type_B == PhysicsServer::SHAPE_RAY, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); - static const CollisionFunc collision_table[5][5] = { + static const CollisionFunc collision_table[6][6] = { { _collision_sphere_sphere<false>, _collision_sphere_box<false>, _collision_sphere_capsule<false>, + _collision_sphere_cylinder<false>, _collision_sphere_convex_polygon<false>, _collision_sphere_face<false> }, { 0, _collision_box_box<false>, _collision_box_capsule<false>, + _collision_box_cylinder<false>, _collision_box_convex_polygon<false>, _collision_box_face<false> }, { 0, 0, _collision_capsule_capsule<false>, + _collision_capsule_cylinder<false>, _collision_capsule_convex_polygon<false>, _collision_capsule_face<false> }, { 0, 0, 0, + _collision_cylinder_cylinder<false>, + _collision_cylinder_convex_polygon<false>, + _collision_cylinder_face<false> }, + { 0, + 0, + 0, + 0, _collision_convex_polygon_convex_polygon<false>, _collision_convex_polygon_face<false> }, { 0, 0, 0, 0, + 0, 0 }, }; - static const CollisionFunc collision_table_margin[5][5] = { + static const CollisionFunc collision_table_margin[6][6] = { { _collision_sphere_sphere<true>, _collision_sphere_box<true>, _collision_sphere_capsule<true>, + _collision_sphere_cylinder<true>, _collision_sphere_convex_polygon<true>, _collision_sphere_face<true> }, { 0, _collision_box_box<true>, _collision_box_capsule<true>, + _collision_box_cylinder<true>, _collision_box_convex_polygon<true>, _collision_box_face<true> }, { 0, 0, _collision_capsule_capsule<true>, + _collision_capsule_cylinder<true>, _collision_capsule_convex_polygon<true>, _collision_capsule_face<true> }, { 0, 0, 0, + _collision_cylinder_cylinder<true>, + _collision_cylinder_convex_polygon<true>, + _collision_cylinder_face<true> }, + { 0, + 0, + 0, + 0, _collision_convex_polygon_convex_polygon<true>, _collision_convex_polygon_face<true> }, { 0, 0, 0, 0, + 0, 0 }, }; diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index a06942cb2a..3a32c46a9b 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -701,20 +701,6 @@ real_t PhysicsServerSW::body_get_param(RID p_body, BodyParameter p_param) const return body->get_param(p_param); }; -void PhysicsServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { - BodySW *body = body_owner.get(p_body); - ERR_FAIL_COND(!body); - - body->set_combine_mode(p_param, p_mode); -} - -PhysicsServer::CombineMode PhysicsServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const { - BodySW *body = body_owner.get(p_body); - ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); - - return body->get_combine_mode(p_param); -} - void PhysicsServerSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { BodySW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 57037fb325..1c5754124d 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -188,10 +188,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value); virtual real_t body_get_param(RID p_body, BodyParameter p_param) const; - /// p_param accept only Bounce and Friction - virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); - virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin); virtual real_t body_get_kinematic_safe_margin(RID p_body) const; diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index fcd2a65ee7..aa063d6c1e 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -405,22 +405,6 @@ void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) { area_angular_damp += p_area->get_angular_damp(); } -void Body2DSW::set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode) { - if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) { - bounce_combine_mode = p_mode; - } else { - friction_combine_mode = p_mode; - } -} - -Physics2DServer::CombineMode Body2DSW::get_combine_mode(Physics2DServer::BodyParameter p_param) const { - if (p_param == Physics2DServer::BODY_PARAM_BOUNCE) { - return bounce_combine_mode; - } else { - return friction_combine_mode; - } -} - void Body2DSW::integrate_forces(real_t p_step) { if (mode == Physics2DServer::BODY_MODE_STATIC) diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index fef233a72b..69184ad484 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -54,8 +54,6 @@ class Body2DSW : public CollisionObject2DSW { real_t mass; real_t bounce; real_t friction; - Physics2DServer::CombineMode bounce_combine_mode; - Physics2DServer::CombineMode friction_combine_mode; real_t _inv_mass; real_t _inv_inertia; @@ -274,12 +272,6 @@ public: _FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; } _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; } - void set_combine_mode(Physics2DServer::BodyParameter p_param, Physics2DServer::CombineMode p_mode); - Physics2DServer::CombineMode get_combine_mode(Physics2DServer::BodyParameter p_param) const; - - _FORCE_INLINE_ Physics2DServer::CombineMode get_bounce_combine_mode() const { return bounce_combine_mode; } - _FORCE_INLINE_ Physics2DServer::CombineMode get_friction_combine_mode() const { return friction_combine_mode; } - void integrate_forces(real_t p_step); void integrate_velocities(real_t p_step); diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index be8dcf6fa8..2633edf7bb 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -220,41 +220,11 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const } real_t combine_bounce(Body2DSW *A, Body2DSW *B) { - const Physics2DServer::CombineMode cm = A->get_bounce_combine_mode(); - - switch (cm) { - case Physics2DServer::COMBINE_MODE_INHERIT: - if (B->get_bounce_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT) - return combine_bounce(B, A); - // else use MAX [This is used when the two bodies doesn't use physical material] - case Physics2DServer::COMBINE_MODE_MAX: - return MAX(A->get_bounce(), B->get_bounce()); - case Physics2DServer::COMBINE_MODE_MIN: - return MIN(A->get_bounce(), B->get_bounce()); - case Physics2DServer::COMBINE_MODE_MULTIPLY: - return A->get_bounce() * B->get_bounce(); - default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE: - return (A->get_bounce() + B->get_bounce()) / 2; - } + return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1); } real_t combine_friction(Body2DSW *A, Body2DSW *B) { - const Physics2DServer::CombineMode cm = A->get_friction_combine_mode(); - - switch (cm) { - case Physics2DServer::COMBINE_MODE_INHERIT: - if (B->get_friction_combine_mode() != Physics2DServer::COMBINE_MODE_INHERIT) - return combine_friction(B, A); - // else use Multiply [This is used when the two bodies doesn't use physical material] - case Physics2DServer::COMBINE_MODE_MULTIPLY: - return A->get_friction() * B->get_friction(); - case Physics2DServer::COMBINE_MODE_MAX: - return MAX(A->get_friction(), B->get_friction()); - case Physics2DServer::COMBINE_MODE_MIN: - return MIN(A->get_friction(), B->get_friction()); - default: // Is always Physics2DServer::COMBINE_MODE_AVERAGE: - return (A->get_friction() + B->get_friction()) / 2; - } + return ABS(MIN(A->get_friction(), B->get_friction())); } bool BodyPair2DSW::setup(real_t p_step) { diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index ba87969eea..15e80bcd5e 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -789,22 +789,6 @@ real_t Physics2DServerSW::body_get_param(RID p_body, BodyParameter p_param) cons return body->get_param(p_param); }; -void Physics2DServerSW::body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) { - - Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND(!body); - - body->set_combine_mode(p_param, p_mode); -} - -Physics2DServer::CombineMode Physics2DServerSW::body_get_combine_mode(RID p_body, BodyParameter p_param) const { - - Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND_V(!body, COMBINE_MODE_INHERIT); - - return body->get_combine_mode(p_param); -} - void Physics2DServerSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { Body2DSW *body = body_owner.get(p_body); diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index 0b8d3f2a31..d4fc44b1d7 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -200,10 +200,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value); virtual real_t body_get_param(RID p_body, BodyParameter p_param) const; - /// p_param accept only Bounce and Friction - virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode); - virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const; - virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant); virtual Variant body_get_state(RID p_body, BodyState p_state) const; diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index b9b0f80805..6b34fb9739 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -211,9 +211,6 @@ public: FUNC3(body_set_param, RID, BodyParameter, real_t); FUNC2RC(real_t, body_get_param, RID, BodyParameter); - FUNC3(body_set_combine_mode, RID, BodyParameter, CombineMode); - FUNC2RC(CombineMode, body_get_combine_mode, RID, BodyParameter); - FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 796eec1e8e..f42d9868f0 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -423,19 +423,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0; virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0; - enum CombineMode { - COMBINE_MODE_MAX, - COMBINE_MODE_MIN, - COMBINE_MODE_MULTIPLY, - COMBINE_MODE_AVERAGE, - - COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction) - }; - - /// p_param accept only Bounce and Friction - virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0; - virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0; - //state enum BodyState { BODY_STATE_TRANSFORM, diff --git a/servers/physics_server.h b/servers/physics_server.h index 294c6b6674..948aec1a2d 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -401,19 +401,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, float p_value) = 0; virtual float body_get_param(RID p_body, BodyParameter p_param) const = 0; - enum CombineMode { - COMBINE_MODE_MAX, - COMBINE_MODE_MIN, - COMBINE_MODE_MULTIPLY, - COMBINE_MODE_AVERAGE, - - COMBINE_MODE_INHERIT /// Inherit from other body or use COMBINE_MODE_MAX (Restitution) COMBINE_MODE_MULTIPLY (Friction) - }; - - /// p_param accept only Bounce and Friction - virtual void body_set_combine_mode(RID p_body, BodyParameter p_param, CombineMode p_mode) = 0; - virtual CombineMode body_get_combine_mode(RID p_body, BodyParameter p_param) const = 0; - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0; virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0; diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index aa0e5c289b..4c764641e3 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -73,7 +73,7 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag usage.vram = E->get().bytes; usage.id = E->get().texture; usage.type = "Texture"; - usage.format = itos(E->get().size.width) + "x" + itos(E->get().size.height) + " " + Image::get_format_name(E->get().format); + usage.format = itos(E->get().width) + "x" + itos(E->get().height) + " " + Image::get_format_name(E->get().format); r_usage->push_back(usage); } } @@ -104,6 +104,7 @@ void register_server_types() { ClassDB::register_virtual_class<AudioStream>(); ClassDB::register_virtual_class<AudioStreamPlayback>(); + ClassDB::register_class<AudioStreamMicrophone>(); ClassDB::register_class<AudioStreamRandomPitch>(); ClassDB::register_virtual_class<AudioEffect>(); ClassDB::register_class<AudioEffectEQ>(); diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 611e25af2a..843773e5b1 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -197,9 +197,10 @@ } #define FUNC5RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - int m_type##allocn() { \ - for (int i = 0; i < m_type##_pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ + List<RID> m_type##_id_pool; \ + int m_type##allocn(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + for (int i = 0; i < pool_max_size; i++) { \ + m_type##_id_pool.push_back(server_name->m_type##_create(p1, p2, p3, p4, p5)); \ } \ return 0; \ } \ diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 5ce4f2b62d..49dff0d557 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -176,17 +176,34 @@ public: /* TEXTURE API */ virtual RID texture_create() = 0; - virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0; - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0; - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0; - virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const = 0; + virtual void texture_allocate(RID p_texture, + int p_width, + int p_height, + int p_depth_3d, + Image::Format p_format, + VS::TextureType p_type, + uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0; + + virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level = 0) = 0; + + virtual void texture_set_data_partial(RID p_texture, + const Ref<Image> &p_image, + int src_x, int src_y, + int src_w, int src_h, + int dst_x, int dst_y, + int p_dst_mip, + int p_level = 0) = 0; + + virtual Ref<Image> texture_get_data(RID p_texture, int p_level = 0) const = 0; virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0; virtual uint32_t texture_get_flags(RID p_texture) const = 0; virtual Image::Format texture_get_format(RID p_texture) const = 0; + virtual VS::TextureType texture_get_type(RID p_texture) const = 0; virtual uint32_t texture_get_texid(RID p_texture) const = 0; virtual uint32_t texture_get_width(RID p_texture) const = 0; virtual uint32_t texture_get_height(RID p_texture) const = 0; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; + virtual uint32_t texture_get_depth(RID p_texture) const = 0; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) = 0; virtual void texture_set_path(RID p_texture, const String &p_path) = 0; virtual String texture_get_path(RID p_texture) const = 0; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index d4fb8d98b0..ca50d0d049 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -123,6 +123,12 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "TYPE_SAMPLER2D", "TYPE_ISAMPLER2D", "TYPE_USAMPLER2D", + "TYPE_SAMPLER2DARRAY", + "TYPE_ISAMPLER2DARRAY", + "TYPE_USAMPLER2DARRAY", + "TYPE_SAMPLER3D", + "TYPE_ISAMPLER3D", + "TYPE_USAMPLER3D", "TYPE_SAMPLERCUBE", "INTERPOLATION_FLAT", "INTERPOLATION_NO_PERSPECTIVE", @@ -257,6 +263,12 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_SAMPLER2D, "sampler2D" }, { TK_TYPE_ISAMPLER2D, "isampler2D" }, { TK_TYPE_USAMPLER2D, "usampler2D" }, + { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray" }, + { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray" }, + { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray" }, + { TK_TYPE_SAMPLER3D, "sampler3D" }, + { TK_TYPE_ISAMPLER3D, "isampler3D" }, + { TK_TYPE_USAMPLER3D, "usampler3D" }, { TK_TYPE_SAMPLERCUBE, "samplerCube" }, { TK_INTERPOLATION_FLAT, "flat" }, { TK_INTERPOLATION_NO_PERSPECTIVE, "noperspective" }, @@ -516,13 +528,14 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { bool hexa_found = false; bool sign_found = false; bool minus_exponent_found = false; + bool float_suffix_found = false; String str; int i = 0; while (true) { if (GETCHAR(i) == '.') { - if (period_found || exponent_found) + if (period_found || exponent_found || hexa_found || float_suffix_found) return _make_token(TK_ERROR, "Invalid numeric constant"); period_found = true; } else if (GETCHAR(i) == 'x') { @@ -530,11 +543,16 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_ERROR, "Invalid numeric constant"); hexa_found = true; } else if (GETCHAR(i) == 'e') { - if (hexa_found || exponent_found) + if (hexa_found || exponent_found || float_suffix_found) return _make_token(TK_ERROR, "Invalid numeric constant"); exponent_found = true; + } else if (GETCHAR(i) == 'f') { + if (hexa_found || exponent_found) + return _make_token(TK_ERROR, "Invalid numeric constant"); + float_suffix_found = true; } else if (_is_number(GETCHAR(i))) { - //all ok + if (float_suffix_found) + return _make_token(TK_ERROR, "Invalid numeric constant"); } else if (hexa_found && _is_hex(GETCHAR(i))) { } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { @@ -550,21 +568,60 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { i++; } - if (!_is_number(str[str.length() - 1])) - return _make_token(TK_ERROR, "Invalid numeric constant"); + CharType last_char = str[str.length() - 1]; + + if (hexa_found) { + //hex integers eg."0xFF" or "0x12AB", etc - NOT supported yet + return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant - Not supported"); + } else if (period_found || float_suffix_found) { + //floats + if (period_found) { + if (float_suffix_found) { + //checks for eg "1.f" or "1.99f" notations + if (last_char != 'f') { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } else { + //checks for eg. "1." or "1.99" notations + if (last_char != '.' && !_is_number(last_char)) { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } + } else if (float_suffix_found) { + // if no period found the float suffix must be the last character, like in "2f" for "2.0" + if (last_char != 'f') { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } + + if (float_suffix_found) { + //strip the suffix + str = str.left(str.length() - 1); + //compensate reading cursor position + char_idx += 1; + } + + if (!str.is_valid_float()) { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } else { + //integers + if (!_is_number(last_char)) { + return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + } + if (!str.is_valid_integer()) { + return _make_token(TK_ERROR, "Invalid numeric constant"); + } + } char_idx += str.length(); Token tk; - if (period_found || minus_exponent_found) + if (period_found || minus_exponent_found || float_suffix_found) tk.type = TK_REAL_CONSTANT; else tk.type = TK_INT_CONSTANT; - if (!str.is_valid_float()) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - - tk.constant = str.to_double(); + tk.constant = str.to_double(); //wont work with hex tk.line = tk_line; return tk; @@ -660,6 +717,12 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) { p_type == TK_TYPE_SAMPLER2D || p_type == TK_TYPE_ISAMPLER2D || p_type == TK_TYPE_USAMPLER2D || + p_type == TK_TYPE_SAMPLER2DARRAY || + p_type == TK_TYPE_ISAMPLER2DARRAY || + p_type == TK_TYPE_USAMPLER2DARRAY || + p_type == TK_TYPE_SAMPLER3D || + p_type == TK_TYPE_ISAMPLER3D || + p_type == TK_TYPE_USAMPLER3D || p_type == TK_TYPE_SAMPLERCUBE); } @@ -731,6 +794,12 @@ String ShaderLanguage::get_datatype_name(DataType p_type) { case TYPE_SAMPLER2D: return "sampler2D"; case TYPE_ISAMPLER2D: return "isampler2D"; case TYPE_USAMPLER2D: return "usampler2D"; + case TYPE_SAMPLER2DARRAY: return "sampler2DArray"; + case TYPE_ISAMPLER2DARRAY: return "isampler2DArray"; + case TYPE_USAMPLER2DARRAY: return "usampler2DArray"; + case TYPE_SAMPLER3D: return "sampler3D"; + case TYPE_ISAMPLER3D: return "isampler3D"; + case TYPE_USAMPLER3D: return "usampler3D"; case TYPE_SAMPLERCUBE: return "samplerCube"; } @@ -1802,6 +1871,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID } }, { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID } }, { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID } }, { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID } }, { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID } }, @@ -1813,6 +1888,24 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID } }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID } }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, @@ -1831,15 +1924,38 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID } }, + { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + + { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID } }, + { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + + { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID } }, + { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } }, { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } }, { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + + { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, @@ -1852,6 +1968,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, + { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, + { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } }, @@ -2139,7 +2261,16 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) { bool ShaderLanguage::is_sampler_type(DataType p_type) { - return p_type == TYPE_SAMPLER2D || p_type == TYPE_ISAMPLER2D || p_type == TYPE_USAMPLER2D || p_type == TYPE_SAMPLERCUBE; + return p_type == TYPE_SAMPLER2D || + p_type == TYPE_ISAMPLER2D || + p_type == TYPE_USAMPLER2D || + p_type == TYPE_SAMPLER2DARRAY || + p_type == TYPE_ISAMPLER2DARRAY || + p_type == TYPE_USAMPLER2DARRAY || + p_type == TYPE_SAMPLER3D || + p_type == TYPE_ISAMPLER3D || + p_type == TYPE_USAMPLER3D || + p_type == TYPE_SAMPLERCUBE; } void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index b5fd567c07..d68f233b2f 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -72,6 +72,12 @@ public: TK_TYPE_SAMPLER2D, TK_TYPE_ISAMPLER2D, TK_TYPE_USAMPLER2D, + TK_TYPE_SAMPLER2DARRAY, + TK_TYPE_ISAMPLER2DARRAY, + TK_TYPE_USAMPLER2DARRAY, + TK_TYPE_SAMPLER3D, + TK_TYPE_ISAMPLER3D, + TK_TYPE_USAMPLER3D, TK_TYPE_SAMPLERCUBE, TK_INTERPOLATION_FLAT, TK_INTERPOLATION_NO_PERSPECTIVE, @@ -186,6 +192,12 @@ public: TYPE_SAMPLER2D, TYPE_ISAMPLER2D, TYPE_USAMPLER2D, + TYPE_SAMPLER2DARRAY, + TYPE_ISAMPLER2DARRAY, + TYPE_USAMPLER2DARRAY, + TYPE_SAMPLER3D, + TYPE_ISAMPLER3D, + TYPE_USAMPLER3D, TYPE_SAMPLERCUBE, }; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index d58be21858..a00b364565 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -148,17 +148,19 @@ public: /* TEXTURE API */ BIND0R(RID, texture_create) - BIND5(texture_allocate, RID, int, int, Image::Format, uint32_t) - BIND3(texture_set_data, RID, const Ref<Image> &, CubeMapSide) - BIND10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, CubeMapSide) - BIND2RC(Ref<Image>, texture_get_data, RID, CubeMapSide) + BIND7(texture_allocate, RID, int, int, int, Image::Format, TextureType, uint32_t) + BIND3(texture_set_data, RID, const Ref<Image> &, int) + BIND10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, int) + BIND2RC(Ref<Image>, texture_get_data, RID, int) BIND2(texture_set_flags, RID, uint32_t) BIND1RC(uint32_t, texture_get_flags, RID) BIND1RC(Image::Format, texture_get_format, RID) + BIND1RC(TextureType, texture_get_type, RID) BIND1RC(uint32_t, texture_get_texid, RID) BIND1RC(uint32_t, texture_get_width, RID) BIND1RC(uint32_t, texture_get_height, RID) - BIND3(texture_set_size_override, RID, int, int) + BIND1RC(uint32_t, texture_get_depth, RID) + BIND4(texture_set_size_override, RID, int, int, int) BIND3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *) BIND3(texture_set_detect_srgb_callback, RID, TextureDetectCallback, void *) diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index c6af960d9f..3a4d72c793 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -82,17 +82,19 @@ public: /* EVENT QUEUING */ FUNCRID(texture) - FUNC5(texture_allocate, RID, int, int, Image::Format, uint32_t) - FUNC3(texture_set_data, RID, const Ref<Image> &, CubeMapSide) - FUNC10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, CubeMapSide) - FUNC2RC(Ref<Image>, texture_get_data, RID, CubeMapSide) + FUNC7(texture_allocate, RID, int, int, int, Image::Format, TextureType, uint32_t) + FUNC3(texture_set_data, RID, const Ref<Image> &, int) + FUNC10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, int) + FUNC2RC(Ref<Image>, texture_get_data, RID, int) FUNC2(texture_set_flags, RID, uint32_t) FUNC1RC(uint32_t, texture_get_flags, RID) FUNC1RC(Image::Format, texture_get_format, RID) + FUNC1RC(TextureType, texture_get_type, RID) FUNC1RC(uint32_t, texture_get_texid, RID) FUNC1RC(uint32_t, texture_get_width, RID) FUNC1RC(uint32_t, texture_get_height, RID) - FUNC3(texture_set_size_override, RID, int, int) + FUNC1RC(uint32_t, texture_get_depth, RID) + FUNC4(texture_set_size_override, RID, int, int, int) FUNC3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *) FUNC3(texture_set_detect_srgb_callback, RID, TextureDetectCallback, void *) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index 2e5b27510a..bc9e9042ec 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -55,7 +55,7 @@ RID VisualServer::texture_create_from_image(const Ref<Image> &p_image, uint32_t ERR_FAIL_COND_V(!p_image.is_valid(), RID()); RID texture = texture_create(); - texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), p_flags); //if it has mipmaps, use, else generate + texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags); //if it has mipmaps, use, else generate ERR_FAIL_COND_V(!texture.is_valid(), texture); texture_set_data(texture, p_image); @@ -72,7 +72,9 @@ Array VisualServer::_texture_debug_usage_bind() { Dictionary dict; dict["texture"] = E->get().texture; - dict["size"] = E->get().size; + dict["width"] = E->get().width; + dict["height"] = E->get().height; + dict["depth"] = E->get().depth; dict["format"] = E->get().format; dict["bytes"] = E->get().bytes; dict["path"] = E->get().path; @@ -333,7 +335,7 @@ RID VisualServer::get_white_texture() { } Ref<Image> white = memnew(Image(4, 4, 0, Image::FORMAT_RGB8, wt)); white_texture = texture_create(); - texture_allocate(white_texture, 4, 4, Image::FORMAT_RGB8); + texture_allocate(white_texture, 4, 4, 0, Image::FORMAT_RGB8, TEXTURE_TYPE_2D); texture_set_data(white_texture, white); return white_texture; } @@ -1658,17 +1660,19 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_create"), &VisualServer::texture_create); ClassDB::bind_method(D_METHOD("texture_create_from_image", "image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); - ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "format", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT)); - ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "cube_side"), &VisualServer::texture_set_data, DEFVAL(CUBEMAP_LEFT)); - ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "cube_side"), &VisualServer::texture_set_data_partial, DEFVAL(CUBEMAP_LEFT)); + ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "depth_3d", "format", "type", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT)); + ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "layer"), &VisualServer::texture_set_data, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "layer"), &VisualServer::texture_set_data_partial, DEFVAL(0)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "cube_side"), &VisualServer::texture_get_data, DEFVAL(CUBEMAP_LEFT)); ClassDB::bind_method(D_METHOD("texture_set_flags", "texture", "flags"), &VisualServer::texture_set_flags); ClassDB::bind_method(D_METHOD("texture_get_flags", "texture"), &VisualServer::texture_get_flags); ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &VisualServer::texture_get_format); + ClassDB::bind_method(D_METHOD("texture_get_type", "texture"), &VisualServer::texture_get_type); ClassDB::bind_method(D_METHOD("texture_get_texid", "texture"), &VisualServer::texture_get_texid); ClassDB::bind_method(D_METHOD("texture_get_width", "texture"), &VisualServer::texture_get_width); ClassDB::bind_method(D_METHOD("texture_get_height", "texture"), &VisualServer::texture_get_height); - ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height"), &VisualServer::texture_set_size_override); + ClassDB::bind_method(D_METHOD("texture_get_depth", "texture"), &VisualServer::texture_get_depth); + ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height", "depth"), &VisualServer::texture_set_size_override); ClassDB::bind_method(D_METHOD("texture_set_path", "texture", "path"), &VisualServer::texture_set_path); ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &VisualServer::texture_get_path); ClassDB::bind_method(D_METHOD("texture_set_shrink_all_x2_on_set_data", "shrink"), &VisualServer::texture_set_shrink_all_x2_on_set_data); @@ -2059,13 +2063,17 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(CUBEMAP_FRONT); BIND_ENUM_CONSTANT(CUBEMAP_BACK); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBEMAP); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D_ARRAY); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D); + BIND_ENUM_CONSTANT(TEXTURE_FLAG_MIPMAPS); BIND_ENUM_CONSTANT(TEXTURE_FLAG_REPEAT); BIND_ENUM_CONSTANT(TEXTURE_FLAG_FILTER); BIND_ENUM_CONSTANT(TEXTURE_FLAG_ANISOTROPIC_FILTER); BIND_ENUM_CONSTANT(TEXTURE_FLAG_CONVERT_TO_LINEAR); BIND_ENUM_CONSTANT(TEXTURE_FLAG_MIRRORED_REPEAT); - BIND_ENUM_CONSTANT(TEXTURE_FLAG_CUBEMAP); BIND_ENUM_CONSTANT(TEXTURE_FLAG_USED_FOR_STREAMING); BIND_ENUM_CONSTANT(TEXTURE_FLAGS_DEFAULT); diff --git a/servers/visual_server.h b/servers/visual_server.h index 6847f6d2ae..0ec902c18c 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -90,11 +90,17 @@ public: TEXTURE_FLAG_ANISOTROPIC_FILTER = 8, TEXTURE_FLAG_CONVERT_TO_LINEAR = 16, TEXTURE_FLAG_MIRRORED_REPEAT = 32, /// Repeat texture, with alternate sections mirrored - TEXTURE_FLAG_CUBEMAP = 2048, - TEXTURE_FLAG_USED_FOR_STREAMING = 4096, + TEXTURE_FLAG_USED_FOR_STREAMING = 2048, TEXTURE_FLAGS_DEFAULT = TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_FILTER }; + enum TextureType { + TEXTURE_TYPE_2D, + TEXTURE_TYPE_CUBEMAP, + TEXTURE_TYPE_2D_ARRAY, + TEXTURE_TYPE_3D, + }; + enum CubeMapSide { CUBEMAP_LEFT, @@ -107,17 +113,33 @@ public: virtual RID texture_create() = 0; RID texture_create_from_image(const Ref<Image> &p_image, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); // helper - virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0; - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0; - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0; - virtual Ref<Image> texture_get_data(RID p_texture, CubeMapSide p_cube_side = CUBEMAP_LEFT) const = 0; + virtual void texture_allocate(RID p_texture, + int p_width, + int p_height, + int p_depth_3d, + Image::Format p_format, + TextureType p_type, + uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0; + + virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; + virtual void texture_set_data_partial(RID p_texture, + const Ref<Image> &p_image, + int src_x, int src_y, + int src_w, int src_h, + int dst_x, int dst_y, + int p_dst_mip, + int p_layer = 0) = 0; + + virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const = 0; virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0; virtual uint32_t texture_get_flags(RID p_texture) const = 0; virtual Image::Format texture_get_format(RID p_texture) const = 0; + virtual TextureType texture_get_type(RID p_texture) const = 0; virtual uint32_t texture_get_texid(RID p_texture) const = 0; virtual uint32_t texture_get_width(RID p_texture) const = 0; virtual uint32_t texture_get_height(RID p_texture) const = 0; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; + virtual uint32_t texture_get_depth(RID p_texture) const = 0; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) = 0; virtual void texture_set_path(RID p_texture, const String &p_path) = 0; virtual String texture_get_path(RID p_texture) const = 0; @@ -132,7 +154,9 @@ public: struct TextureInfo { RID texture; - Size2 size; + uint32_t width; + uint32_t height; + uint32_t depth; Image::Format format; int bytes; String path; @@ -1054,6 +1078,7 @@ VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOQuality); VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOBlur); VARIANT_ENUM_CAST(VisualServer::InstanceFlags); VARIANT_ENUM_CAST(VisualServer::ShadowCastingSetting); +VARIANT_ENUM_CAST(VisualServer::TextureType); //typedef VisualServer VS; // makes it easier to use #define VS VisualServer diff --git a/thirdparty/glad/glad.c b/thirdparty/glad/glad.c index dd6fe8b8f3..35469e9031 100644 --- a/thirdparty/glad/glad.c +++ b/thirdparty/glad/glad.c @@ -77,7 +77,7 @@ void close_gl(void) { #include <dlfcn.h> static void* libGL; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__HAIKU__) typedef void* (APIENTRYP PFNGLXGETPROCADDRESSPROC_PRIVATE)(const char*); static PFNGLXGETPROCADDRESSPROC_PRIVATE gladGetProcAddressPtr; #endif @@ -100,7 +100,7 @@ int open_gl(void) { libGL = dlopen(NAMES[index], RTLD_NOW | RTLD_GLOBAL); if(libGL != NULL) { -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__HAIKU__) return 1; #else gladGetProcAddressPtr = (PFNGLXGETPROCADDRESSPROC_PRIVATE)dlsym(libGL, @@ -127,7 +127,7 @@ void* get_proc(const char *namez) { void* result = NULL; if(libGL == NULL) return NULL; -#ifndef __APPLE__ +#if !defined(__APPLE__) && !defined(__HAIKU__) if(gladGetProcAddressPtr != NULL) { result = gladGetProcAddressPtr(namez); } diff --git a/thirdparty/libwebsockets/lws_config.h b/thirdparty/libwebsockets/lws_config.h index 7185a806a5..e5e15cc2fd 100644 --- a/thirdparty/libwebsockets/lws_config.h +++ b/thirdparty/libwebsockets/lws_config.h @@ -174,7 +174,7 @@ #define LWS_HAVE_MALLOC_H #endif -#if !defined(IPHONE_ENABLED) && !defined(OSX_ENABLED) +#if !defined(IPHONE_ENABLED) && !defined(OSX_ENABLED) && !defined(__HAIKU__) #define LWS_HAVE_PIPE2 #endif diff --git a/thirdparty/libwebsockets/lws_config_private.h b/thirdparty/libwebsockets/lws_config_private.h index 9d04078fef..b26d225afa 100644 --- a/thirdparty/libwebsockets/lws_config_private.h +++ b/thirdparty/libwebsockets/lws_config_private.h @@ -81,7 +81,7 @@ /* Define to 1 if you have the <sys/prctl.h> header file. */ #define LWS_HAVE_SYS_PRCTL_H -#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) || defined(__FreeBSD__) || defined(__OpenBSD__) +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) #undef LWS_HAVE_SYS_PRCTL_H #endif diff --git a/thirdparty/thekla_atlas/nvcore/nvcore.h b/thirdparty/thekla_atlas/nvcore/nvcore.h index a3deb66be2..5ef69668d9 100644 --- a/thirdparty/thekla_atlas/nvcore/nvcore.h +++ b/thirdparty/thekla_atlas/nvcore/nvcore.h @@ -44,6 +44,9 @@ #elif defined POSH_OS_FREEBSD # define NV_OS_FREEBSD 1 # define NV_OS_UNIX 1 +#elif defined POSH_OS_HAIKU +# define NV_OS_HAIKU 1 +# define NV_OS_UNIX 1 #elif defined POSH_OS_OPENBSD # define NV_OS_OPENBSD 1 # define NV_OS_UNIX 1 @@ -341,7 +344,7 @@ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N]; #elif NV_CC_GNUC # if NV_OS_LINUX # include "DefsGnucLinux.h" -# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD +# elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_HAIKU # include "DefsGnucDarwin.h" # elif NV_OS_ORBIS # include "DefsOrbis.h" diff --git a/thirdparty/thekla_atlas/nvmath/nvmath.h b/thirdparty/thekla_atlas/nvmath/nvmath.h index f2b69426e1..a697f9293d 100644 --- a/thirdparty/thekla_atlas/nvmath/nvmath.h +++ b/thirdparty/thekla_atlas/nvmath/nvmath.h @@ -181,10 +181,8 @@ namespace nv { #if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO return _finite(f) != 0; -#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS +#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX return isfinite(f); -#elif NV_OS_LINUX - return finitef(f); #else # error "isFinite not supported" #endif @@ -196,10 +194,8 @@ namespace nv { #if NV_OS_WIN32 || NV_OS_XBOX || NV_OS_DURANGO return _isnan(f) != 0; -#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS +#elif NV_OS_DARWIN || NV_OS_FREEBSD || NV_OS_OPENBSD || NV_OS_ORBIS || NV_OS_LINUX return isnan(f); -#elif NV_OS_LINUX - return isnanf(f); #else # error "isNan not supported" #endif diff --git a/thirdparty/thekla_atlas/poshlib/posh.h b/thirdparty/thekla_atlas/poshlib/posh.h index 3038297b39..72acd20ce0 100644 --- a/thirdparty/thekla_atlas/poshlib/posh.h +++ b/thirdparty/thekla_atlas/poshlib/posh.h @@ -298,6 +298,11 @@ Metrowerks: # define POSH_OS_STRING "Linux" #endif +#if defined __HAIKU__ +# define POSH_OS_HAIKU 1 +# define POSH_OS_STRING "Haiku" +#endif + #if defined __FreeBSD__ # define POSH_OS_FREEBSD 1 # define POSH_OS_STRING "FreeBSD" |