diff options
Diffstat (limited to 'core')
35 files changed, 2125 insertions, 1131 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index 0f217c8235..cfd7677d6b 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -33,6 +33,7 @@ #include "geometry.h" #include "io/file_access_compressed.h" #include "io/file_access_encrypted.h" +#include "io/json.h" #include "io/marshalls.h" #include "os/keyboard.h" #include "os/os.h" @@ -440,8 +441,8 @@ bool _OS::is_vsync_enabled() const { return OS::get_singleton()->is_vsync_enabled(); } -PowerState _OS::get_power_state() { - return OS::get_singleton()->get_power_state(); +_OS::PowerState _OS::get_power_state() { + return _OS::PowerState(OS::get_singleton()->get_power_state()); } int _OS::get_power_seconds_left() { @@ -2600,3 +2601,76 @@ _Engine *_Engine::singleton = NULL; _Engine::_Engine() { singleton = this; } + +void JSONParseResult::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_error"), &JSONParseResult::get_error); + ClassDB::bind_method(D_METHOD("get_error_string"), &JSONParseResult::get_error_string); + ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParseResult::get_error_line); + ClassDB::bind_method(D_METHOD("get_result"), &JSONParseResult::get_result); + + ClassDB::bind_method(D_METHOD("set_error", "error"), &JSONParseResult::set_error); + ClassDB::bind_method(D_METHOD("set_error_string", "error_string"), &JSONParseResult::set_error_string); + ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line); + ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result); + + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error"); + ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string"); + ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line"); + ADD_PROPERTYNZ(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result"); +} + +void JSONParseResult::set_error(Error p_error) { + error = p_error; +} + +Error JSONParseResult::get_error() const { + return error; +} + +void JSONParseResult::set_error_string(const String &p_error_string) { + error_string = p_error_string; +} + +String JSONParseResult::get_error_string() const { + return error_string; +} + +void JSONParseResult::set_error_line(int p_error_line) { + error_line = p_error_line; +} + +int JSONParseResult::get_error_line() const { + return error_line; +} + +void JSONParseResult::set_result(const Variant &p_result) { + result = p_result; +} + +Variant JSONParseResult::get_result() const { + return result; +} + +void _JSON::_bind_methods() { + ClassDB::bind_method(D_METHOD("print", "value"), &_JSON::print); + ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse); +} + +String _JSON::print(const Variant &p_value) { + return JSON::print(p_value); +} + +Ref<JSONParseResult> _JSON::parse(const String &p_json) { + Ref<JSONParseResult> result; + result.instance(); + + result->error = JSON::parse(p_json, result->result, result->error_string, result->error_line); + + return result; +} + +_JSON *_JSON::singleton = NULL; + +_JSON::_JSON() { + singleton = this; +} diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index 1a3782c471..721acf657f 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -36,7 +36,7 @@ #include "io/resource_saver.h" #include "os/dir_access.h" #include "os/file_access.h" -#include "os/power.h" +#include "os/os.h" #include "os/semaphore.h" #include "os/thread.h" @@ -97,6 +97,14 @@ protected: static _OS *singleton; public: + enum PowerState { + POWERSTATE_UNKNOWN, /**< cannot determine power status */ + POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */ + POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */ + POWERSTATE_CHARGING, /**< Plugged in, charging battery */ + POWERSTATE_CHARGED /**< Plugged in, battery charged */ + }; + enum Weekday { DAY_SUNDAY, DAY_MONDAY, @@ -312,6 +320,7 @@ public: _OS(); }; +VARIANT_ENUM_CAST(_OS::PowerState); VARIANT_ENUM_CAST(_OS::Weekday); VARIANT_ENUM_CAST(_OS::Month); VARIANT_ENUM_CAST(_OS::SystemDir); @@ -660,4 +669,50 @@ public: _Engine(); }; +class _JSON; + +class JSONParseResult : public Reference { + GDCLASS(JSONParseResult, Reference) + + friend class _JSON; + + Error error; + String error_string; + int error_line; + + Variant result; + +protected: + static void _bind_methods(); + +public: + void set_error(Error p_error); + Error get_error() const; + + void set_error_string(const String &p_error_string); + String get_error_string() const; + + void set_error_line(int p_error_line); + int get_error_line() const; + + void set_result(const Variant &p_result); + Variant get_result() const; +}; + +class _JSON : public Object { + GDCLASS(_JSON, Object) + +protected: + static void _bind_methods(); + static _JSON *singleton; + +public: + static _JSON *get_singleton() { return singleton; } + + String print(const Variant &p_value); + Ref<JSONParseResult> parse(const String &p_json); + + _JSON(); +}; + #endif // CORE_BIND_H diff --git a/core/color.cpp b/core/color.cpp index 1f8934ed05..78b11a84df 100644 --- a/core/color.cpp +++ b/core/color.cpp @@ -34,7 +34,7 @@ #include "math_funcs.h" #include "print_string.h" -uint32_t Color::to_ARGB32() const { +uint32_t Color::to_argb32() const { uint32_t c = (uint8_t)(a * 255); c <<= 8; @@ -47,7 +47,7 @@ uint32_t Color::to_ARGB32() const { return c; } -uint32_t Color::to_ABGR32() const { +uint32_t Color::to_abgr32() const { uint32_t c = (uint8_t)(a * 255); c <<= 8; c |= (uint8_t)(b * 255); @@ -59,15 +59,15 @@ uint32_t Color::to_ABGR32() const { return c; } -uint32_t Color::to_32() const { +uint32_t Color::to_rgba32() const { - uint32_t c = (uint8_t)(a * 255); - c <<= 8; - c |= (uint8_t)(r * 255); + uint32_t c = (uint8_t)(r * 255); c <<= 8; c |= (uint8_t)(g * 255); c <<= 8; c |= (uint8_t)(b * 255); + c <<= 8; + c |= (uint8_t)(a * 255); return c; } @@ -408,3 +408,122 @@ Color::operator String() const { return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a); } + +Color Color::operator+(const Color &p_color) const { + + return Color( + CLAMP(r + p_color.r, 0.0, 1.0), + CLAMP(g + p_color.g, 0.0, 1.0), + CLAMP(b + p_color.b, 0.0, 1.0), + CLAMP(a + p_color.a, 0.0, 1.0)); +} + +void Color::operator+=(const Color &p_color) { + + r = CLAMP(r + p_color.r, 0.0, 1.0); + g = CLAMP(g + p_color.g, 0.0, 1.0); + b = CLAMP(b + p_color.b, 0.0, 1.0); + a = CLAMP(a + p_color.a, 0.0, 1.0); +} + +Color Color::operator-(const Color &p_color) const { + + return Color( + CLAMP(r - p_color.r, 0.0, 1.0), + CLAMP(g - p_color.g, 0.0, 1.0), + CLAMP(b - p_color.b, 0.0, 1.0), + CLAMP(a - p_color.a, 0.0, 1.0)); +} + +void Color::operator-=(const Color &p_color) { + + r = CLAMP(r - p_color.r, 0.0, 1.0); + g = CLAMP(g - p_color.g, 0.0, 1.0); + b = CLAMP(b - p_color.b, 0.0, 1.0); + a = CLAMP(a - p_color.a, 0.0, 1.0); +} + +Color Color::operator*(const Color &p_color) const { + + return Color( + CLAMP(r * p_color.r, 0.0, 1.0), + CLAMP(g * p_color.g, 0.0, 1.0), + CLAMP(b * p_color.b, 0.0, 1.0), + CLAMP(a * p_color.a, 0.0, 1.0)); +} + +Color Color::operator*(const real_t &rvalue) const { + + return Color( + CLAMP(r * rvalue, 0.0, 1.0), + CLAMP(g * rvalue, 0.0, 1.0), + CLAMP(b * rvalue, 0.0, 1.0), + CLAMP(a * rvalue, 0.0, 1.0)); +} + +void Color::operator*=(const Color &p_color) { + + r = CLAMP(r * p_color.r, 0.0, 1.0); + g = CLAMP(g * p_color.g, 0.0, 1.0); + b = CLAMP(b * p_color.b, 0.0, 1.0); + a = CLAMP(a * p_color.a, 0.0, 1.0); +} + +void Color::operator*=(const real_t &rvalue) { + + r = CLAMP(r * rvalue, 0.0, 1.0); + g = CLAMP(g * rvalue, 0.0, 1.0); + b = CLAMP(b * rvalue, 0.0, 1.0); + a = CLAMP(a * rvalue, 0.0, 1.0); +}; + +Color Color::operator/(const Color &p_color) const { + + return Color( + p_color.r == 0 ? 1 : CLAMP(r / p_color.r, 0.0, 1.0), + p_color.g == 0 ? 1 : CLAMP(g / p_color.g, 0.0, 1.0), + p_color.b == 0 ? 1 : CLAMP(b / p_color.b, 0.0, 1.0), + p_color.a == 0 ? 1 : CLAMP(a / p_color.a, 0.0, 1.0)); +} + +Color Color::operator/(const real_t &rvalue) const { + + if (rvalue == 0) return Color(1.0, 1.0, 1.0, 1.0); + return Color( + CLAMP(r / rvalue, 0.0, 1.0), + CLAMP(g / rvalue, 0.0, 1.0), + CLAMP(b / rvalue, 0.0, 1.0), + CLAMP(a / rvalue, 0.0, 1.0)); +} + +void Color::operator/=(const Color &p_color) { + + r = p_color.r == 0 ? 1 : CLAMP(r / p_color.r, 0.0, 1.0); + g = p_color.g == 0 ? 1 : CLAMP(g / p_color.g, 0.0, 1.0); + b = p_color.b == 0 ? 1 : CLAMP(b / p_color.b, 0.0, 1.0); + a = p_color.a == 0 ? 1 : CLAMP(a / p_color.a, 0.0, 1.0); +} + +void Color::operator/=(const real_t &rvalue) { + + if (rvalue == 0) { + r = 1.0; + g = 1.0; + b = 1.0; + a = 1.0; + } else { + r = CLAMP(r / rvalue, 0.0, 1.0); + g = CLAMP(g / rvalue, 0.0, 1.0); + b = CLAMP(b / rvalue, 0.0, 1.0); + a = CLAMP(a / rvalue, 0.0, 1.0); + } +}; + +Color Color::operator-() const { + + return Color( + CLAMP(1.0 - r, 0.0, 1.0), + CLAMP(1.0 - g, 0.0, 1.0), + CLAMP(1.0 - b, 0.0, 1.0), + CLAMP(1.0 - a, 0.0, 1.0)); +} diff --git a/core/color.h b/core/color.h index cd5510cf01..972b6a1b33 100644 --- a/core/color.h +++ b/core/color.h @@ -51,9 +51,9 @@ struct Color { bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); } bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); } - uint32_t to_32() const; - uint32_t to_ARGB32() const; - uint32_t to_ABGR32() const; + uint32_t to_rgba32() const; + uint32_t to_argb32() const; + uint32_t to_abgr32() const; float gray() const; float get_h() const; float get_s() const; @@ -67,6 +67,23 @@ struct Color { return components[idx]; } + Color operator+(const Color &p_color) const; + void operator+=(const Color &p_color); + + Color operator-() const; + Color operator-(const Color &p_color) const; + void operator-=(const Color &p_color); + + Color operator*(const Color &p_color) const; + Color operator*(const real_t &rvalue) const; + void operator*=(const Color &p_color); + void operator*=(const real_t &rvalue); + + Color operator/(const Color &p_color) const; + Color operator/(const real_t &rvalue) const; + void operator/=(const Color &p_color); + void operator/=(const real_t &rvalue); + void invert(); void contrast(); Color inverted() const; diff --git a/core/event_queue.cpp b/core/event_queue.cpp deleted file mode 100644 index 12f9942a07..0000000000 --- a/core/event_queue.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/*************************************************************************/ -/* event_queue.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 "event_queue.h" - -Error EventQueue::push_call(uint32_t p_instance_ID, const StringName &p_method, VARIANT_ARG_DECLARE) { - - uint8_t room_needed = sizeof(Event); - int args = 0; - if (p_arg5.get_type() != Variant::NIL) - args = 5; - else if (p_arg4.get_type() != Variant::NIL) - args = 4; - else if (p_arg3.get_type() != Variant::NIL) - args = 3; - else if (p_arg2.get_type() != Variant::NIL) - args = 2; - else if (p_arg1.get_type() != Variant::NIL) - args = 1; - else - args = 0; - - room_needed += sizeof(Variant) * args; - - ERR_FAIL_COND_V((buffer_end + room_needed) >= buffer_size, ERR_OUT_OF_MEMORY); - Event *ev = memnew_placement(&event_buffer[buffer_end], Event); - ev->args = args; - ev->instance_ID = p_instance_ID; - ev->method = p_method; - - buffer_end += sizeof(Event); - - if (args >= 1) { - - Variant *v = memnew_placement(&event_buffer[buffer_end], Variant); - buffer_end += sizeof(Variant); - *v = p_arg1; - } - - if (args >= 2) { - - Variant *v = memnew_placement(&event_buffer[buffer_end], Variant); - buffer_end += sizeof(Variant); - *v = p_arg2; - } - - if (args >= 3) { - - Variant *v = memnew_placement(&event_buffer[buffer_end], Variant); - buffer_end += sizeof(Variant); - *v = p_arg3; - } - - if (args >= 4) { - - Variant *v = memnew_placement(&event_buffer[buffer_end], Variant); - buffer_end += sizeof(Variant); - *v = p_arg4; - } - - if (args >= 5) { - - Variant *v = memnew_placement(&event_buffer[buffer_end], Variant); - buffer_end += sizeof(Variant); - *v = p_arg5; - } - - if (buffer_end > buffer_max_used) - buffer_max_used = buffer_end; - - return OK; -} - -void EventQueue::flush_events() { - - uint32_t read_pos = 0; - - while (read_pos < buffer_end) { - - Event *event = (Event *)&event_buffer[read_pos]; - Variant *args = (Variant *)(event + 1); - Object *obj = ObjectDB::get_instance(event->instance_ID); - - if (obj) { - // events don't expect a return value - obj->call(event->method, - (event->args >= 1) ? args[0] : Variant(), - (event->args >= 2) ? args[1] : Variant(), - (event->args >= 3) ? args[2] : Variant(), - (event->args >= 4) ? args[3] : Variant(), - (event->args >= 5) ? args[4] : Variant()); - } - - if (event->args >= 1) args[0].~Variant(); - if (event->args >= 2) args[1].~Variant(); - if (event->args >= 3) args[2].~Variant(); - if (event->args >= 4) args[3].~Variant(); - if (event->args >= 5) args[4].~Variant(); - event->~Event(); - - read_pos += sizeof(Event) + sizeof(Variant) * event->args; - } - - buffer_end = 0; // reset buffer -} - -EventQueue::EventQueue(uint32_t p_buffer_size) { - - buffer_end = 0; - buffer_max_used = 0; - buffer_size = p_buffer_size; - event_buffer = memnew_arr(uint8_t, buffer_size); -} -EventQueue::~EventQueue() { - - uint32_t read_pos = 0; - - while (read_pos < buffer_end) { - - Event *event = (Event *)&event_buffer[read_pos]; - Variant *args = (Variant *)(event + 1); - for (int i = 0; i < event->args; i++) - args[i].~Variant(); - event->~Event(); - - read_pos += sizeof(Event) + sizeof(Variant) * event->args; - } - - memdelete_arr(event_buffer); - event_buffer = NULL; -} diff --git a/core/event_queue.h b/core/event_queue.h deleted file mode 100644 index af1a760945..0000000000 --- a/core/event_queue.h +++ /dev/null @@ -1,64 +0,0 @@ -/*************************************************************************/ -/* event_queue.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ -#ifndef EVENT_QUEUE_H -#define EVENT_QUEUE_H - -#include "object.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ -class EventQueue { - - enum { - - DEFAULT_EVENT_QUEUE_SIZE_KB = 256 - }; - - struct Event { - - uint32_t instance_ID; - StringName method; - int args; - }; - - uint8_t *event_buffer; - uint32_t buffer_end; - uint32_t buffer_max_used; - uint32_t buffer_size; - -public: - Error push_call(uint32_t p_instance_ID, const StringName &p_method, VARIANT_ARG_LIST); - void flush_events(); - - EventQueue(uint32_t p_buffer_size = DEFAULT_EVENT_QUEUE_SIZE_KB * 1024); - ~EventQueue(); -}; - -#endif diff --git a/core/hash_map.h b/core/hash_map.h index 37391a4c83..e100d7a904 100644 --- a/core/hash_map.h +++ b/core/hash_map.h @@ -37,39 +37,6 @@ #include "os/memory.h" #include "ustring.h" -struct HashMapHasherDefault { - static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } - static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } - static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } - - static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); } - static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); } - static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_djb2_one_float(p_double); } - static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; } - static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; } - static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; } - //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } -}; - -template <typename T> -struct HashMapComparatorDefault { - static bool compare(const T &p_lhs, const T &p_rhs) { - return p_lhs == p_rhs; - } - - bool compare(const float &p_lhs, const float &p_rhs) { - return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); - } - - bool compare(const double &p_lhs, const double &p_rhs) { - return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); - } -}; - /** * @class HashMap * @author Juan Linietsky <reduzio@gmail.com> diff --git a/core/hashfuncs.h b/core/hashfuncs.h index 56d40f1dd7..2880cc451e 100644 --- a/core/hashfuncs.h +++ b/core/hashfuncs.h @@ -33,6 +33,7 @@ #include "math_defs.h" #include "math_funcs.h" #include "typedefs.h" +#include "ustring.h" /** * Hashing functions @@ -128,4 +129,37 @@ static inline uint64_t make_uint64_t(T p_in) { return _u._u64; } +struct HashMapHasherDefault { + static _FORCE_INLINE_ uint32_t hash(const String &p_string) { return p_string.hash(); } + static _FORCE_INLINE_ uint32_t hash(const char *p_cstr) { return hash_djb2(p_cstr); } + static _FORCE_INLINE_ uint32_t hash(const uint64_t p_int) { return hash_one_uint64(p_int); } + + static _FORCE_INLINE_ uint32_t hash(const int64_t p_int) { return hash(uint64_t(p_int)); } + static _FORCE_INLINE_ uint32_t hash(const float p_float) { return hash_djb2_one_float(p_float); } + static _FORCE_INLINE_ uint32_t hash(const double p_double) { return hash_djb2_one_float(p_double); } + static _FORCE_INLINE_ uint32_t hash(const uint32_t p_int) { return p_int; } + static _FORCE_INLINE_ uint32_t hash(const int32_t p_int) { return (uint32_t)p_int; } + static _FORCE_INLINE_ uint32_t hash(const uint16_t p_int) { return p_int; } + static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return (uint32_t)p_int; } + static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return p_int; } + static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return (uint32_t)p_int; } + static _FORCE_INLINE_ uint32_t hash(const wchar_t p_wchar) { return (uint32_t)p_wchar; } + //static _FORCE_INLINE_ uint32_t hash(const void* p_ptr) { return uint32_t(uint64_t(p_ptr))*(0x9e3779b1L); } +}; + +template <typename T> +struct HashMapComparatorDefault { + static bool compare(const T &p_lhs, const T &p_rhs) { + return p_lhs == p_rhs; + } + + bool compare(const float &p_lhs, const float &p_rhs) { + return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); + } + + bool compare(const double &p_lhs, const double &p_rhs) { + return (p_lhs == p_rhs) || (Math::is_nan(p_lhs) && Math::is_nan(p_rhs)); + } +}; + #endif diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index d8b8c8c200..58ca2d4c58 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -87,6 +87,8 @@ void FileAccessNetworkClient::_thread_func() { DEBUG_PRINT("SEM WAIT - " + itos(sem->get())); Error err = sem->wait(); + if (err != OK) + ERR_PRINT("sem->wait() failed"); DEBUG_TIME("sem_unlock"); //DEBUG_PRINT("semwait returned "+itos(werr)); DEBUG_PRINT("MUTEX LOCK " + itos(lockcount)); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 661eba2106..16ec6cd3c5 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -37,7 +37,7 @@ #include "core/version.h" //#define print_bl(m_what) print_line(m_what) -#define print_bl(m_what) +#define print_bl(m_what) (void)(m_what) enum { @@ -854,12 +854,6 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { } bool big_endian = f->get_32(); -#ifdef BIG_ENDIAN_ENABLED - endian_swap = !big_endian; -#else - bool endian_swap = big_endian; -#endif - bool use_real64 = f->get_32(); f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian @@ -869,7 +863,11 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { uint32_t ver_format = f->get_32(); print_bl("big endian: " + itos(big_endian)); - print_bl("endian swap: " + itos(endian_swap)); +#ifdef BIG_ENDIAN_ENABLED + print_bl("endian swap: " + itos(!big_endian)); +#else + print_bl("endian swap: " + itos(big_endian)); +#endif print_bl("real64: " + itos(use_real64)); print_bl("major: " + itos(ver_major)); print_bl("minor: " + itos(ver_minor)); @@ -964,18 +962,12 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) { } bool big_endian = f->get_32(); -#ifdef BIG_ENDIAN_ENABLED - endian_swap = !big_endian; -#else - bool endian_swap = big_endian; -#endif - - bool use_real64 = f->get_32(); + f->get_32(); // use_real64 f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian uint32_t ver_major = f->get_32(); - uint32_t ver_minor = f->get_32(); + f->get_32(); // ver_minor uint32_t ver_format = f->get_32(); if (ver_format > FORMAT_VERSION || ver_major > VERSION_MAJOR) { @@ -993,8 +985,6 @@ ResourceInteractiveLoaderBinary::ResourceInteractiveLoaderBinary() { f = NULL; stage = 0; - endian_swap = false; - use_real64 = false; error = OK; translation_remapped = false; } @@ -1123,16 +1113,14 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons } bool big_endian = f->get_32(); -#ifdef BIG_ENDIAN_ENABLED - endian_swap = !big_endian; -#else - bool endian_swap = big_endian; -#endif - bool use_real64 = f->get_32(); f->set_endian_swap(big_endian != 0); //read big endian if saved as big endian - fw->store_32(endian_swap); +#ifdef BIG_ENDIAN_ENABLED + fw->store_32(!big_endian); +#else + fw->store_32(big_endian); +#endif fw->set_endian_swap(big_endian != 0); fw->store_32(use_real64); //use real64 @@ -1793,8 +1781,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const RES &p } save_unicode_string(p_resource->get_class()); - uint64_t md_at = f->get_pos(); - f->store_64(0); //offset to impoty metadata + f->store_64(0); //offset to import metadata for (int i = 0; i < 14; i++) f->store_32(0); // reserved diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index ab77c2c9d3..2316f05b3c 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -44,8 +44,6 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader { FileAccess *f; - bool endian_swap; - bool use_real64; uint64_t importmd_ofs; Vector<char> str_buf; diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 21516ac768..d1afcec18f 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -129,6 +129,16 @@ bool AStar::has_point(int p_id) const { return points.has(p_id); } +Array AStar::get_points() { + Array point_list; + + for (const Map<int, Point *>::Element *E = points.front(); E; E = E->next()) { + point_list.push_back(E->key()); + } + + return point_list; +} + bool AStar::are_points_connected(int p_id, int p_with_id) const { Segment s(p_id, p_with_id); @@ -407,6 +417,7 @@ void AStar::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_weight_scale", "id"), &AStar::get_point_weight_scale); ClassDB::bind_method(D_METHOD("remove_point", "id"), &AStar::remove_point); ClassDB::bind_method(D_METHOD("has_point", "id"), &AStar::has_point); + ClassDB::bind_method(D_METHOD("get_points"), &AStar::get_points); ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar::connect_points, DEFVAL(true)); ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points); diff --git a/core/math/a_star.h b/core/math/a_star.h index 75b860d0a4..38d13d510b 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -105,6 +105,7 @@ public: real_t get_point_weight_scale(int p_id) const; void remove_point(int p_id); bool has_point(int p_id) const; + Array get_points(); void connect_points(int p_id, int p_with_id, bool bidirectional = true); void disconnect_points(int p_id, int p_with_id); diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index b7a929c8e0..2c587762e8 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -131,7 +131,6 @@ void CameraMatrix::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_ void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_dist, real_t p_display_width, real_t p_display_to_lens, real_t p_oversample, real_t p_z_near, real_t p_z_far) { // we first calculate our base frustum on our values without taking our lens magnification into account. - real_t display_to_eye = 2.0 * p_display_to_lens; real_t f1 = (p_intraocular_dist * 0.5) / p_display_to_lens; real_t f2 = ((p_display_width - p_intraocular_dist) * 0.5) / p_display_to_lens; real_t f3 = (p_display_width / 4.0) / p_display_to_lens; @@ -578,7 +577,7 @@ real_t CameraMatrix::get_fov() const { if ((matrix[8] == 0) && (matrix[9] == 0)) { return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; } else { - // our frustum is asymetrical need to calculate the left planes angle seperately.. + // our frustum is asymmetrical need to calculate the left planes angle separately.. Plane left_plane = Plane(matrix[3] + matrix[0], matrix[7] + matrix[4], matrix[11] + matrix[8], diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 614104f698..3b246cb183 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -158,7 +158,7 @@ void TriangleMesh::create(const PoolVector<Vector3> &p_faces) { max_depth = 0; int max_alloc = fc; - int max = _create_bvh(bw.ptr(), bwp.ptr(), 0, fc, 1, max_depth, max_alloc); + _create_bvh(bw.ptr(), bwp.ptr(), 0, fc, 1, max_depth, max_alloc); bw = PoolVector<BVH>::Write(); //clearup bvh.resize(max_alloc); //resize back diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h new file mode 100644 index 0000000000..66a1e348a1 --- /dev/null +++ b/core/oa_hash_map.h @@ -0,0 +1,593 @@ +/*************************************************************************/ +/* oa_hash_map.h */ +/*************************************************************************/ +/* 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. */ +/*************************************************************************/ +#ifndef OA_HASH_MAP_H +#define OA_HASH_MAP_H + +#include "hashfuncs.h" +#include "math_funcs.h" +#include "os/copymem.h" +#include "os/memory.h" + +// uncomment this to disable intial local storage. +#define OA_HASH_MAP_INITIAL_LOCAL_STORAGE + +/** + * This class implements a hash map datastructure that uses open addressing with + * local probing. + * + * It can give huge performance improvements over a chained HashMap because of + * the increased data locality. + * + * Because of that locality property it's important to not use "large" value + * types as the "TData" type. If TData values are too big it can cause more + * cache misses then chaining. If larger values are needed then storing those + * in a separate array and using pointers or indices to reference them is the + * better solution. + * + * This hash map also implements real-time incremental rehashing. + * + */ +template <class TKey, class TData, + uint16_t INITIAL_NUM_ELEMENTS = 64, + class Hasher = HashMapHasherDefault, + class Comparator = HashMapComparatorDefault<TKey> > +class OAHashMap { + +private: +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + TData local_data[INITIAL_NUM_ELEMENTS]; + TKey local_keys[INITIAL_NUM_ELEMENTS]; + uint32_t local_hashes[INITIAL_NUM_ELEMENTS]; + uint8_t local_flags[INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)]; +#endif + + struct { + TData *data; + TKey *keys; + uint32_t *hashes; + + // This is actually an array of bits, 4 bit pairs per octet. + // | ba ba ba ba | ba ba ba ba | .... + // + // if a is set it means that there is an element present. + // if b is set it means that an element was deleted. This is needed for + // the local probing to work without relocating any succeeding and + // colliding entries. + uint8_t *flags; + + uint32_t capacity; + } table, old_table; + + bool is_rehashing; + uint32_t rehash_position; + uint32_t rehash_amount; + + uint32_t elements; + + /* Methods */ + + // returns true if the value already existed, false if it's a new entry + bool _raw_set_with_hash(uint32_t p_hash, const TKey &p_key, const TData &p_data) { + for (int i = 0; i < table.capacity; i++) { + + int pos = (p_hash + i) % table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset)); + bool is_deleted_flag = table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1)); + + if (is_filled_flag) { + if (table.hashes[pos] == p_hash && Comparator::compare(table.keys[pos], p_key)) { + table.data[pos] = p_data; + return true; + } + continue; + } + + table.keys[pos] = p_key; + table.data[pos] = p_data; + table.hashes[pos] = p_hash; + + table.flags[flags_pos] |= (1 << (2 * flags_pos_offset)); + table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset + 1)); + + return false; + } + return false; + } + +public: + _FORCE_INLINE_ uint32_t get_capacity() const { return table.capacity; } + _FORCE_INLINE_ uint32_t get_num_elements() const { return elements; } + + void set(const TKey &p_key, const TData &p_data) { + + uint32_t hash = Hasher::hash(p_key); + + // We don't progress the rehashing if the table just got resized + // to keep the cost of this function low. + if (is_rehashing) { + + // rehash progress + + for (int i = 0; i <= rehash_amount && rehash_position < old_table.capacity; rehash_position++) { + + int flags_pos = rehash_position / 4; + int flags_pos_offset = rehash_position % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + _raw_set_with_hash(old_table.hashes[rehash_position], old_table.keys[rehash_position], old_table.data[rehash_position]); + + old_table.keys[rehash_position].~TKey(); + old_table.data[rehash_position].~TData(); + + memnew_placement(&old_table.keys[rehash_position], TKey); + memnew_placement(&old_table.data[rehash_position], TData); + + old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); + old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); + } + } + + if (rehash_position >= old_table.capacity) { + + // wohooo, we can get rid of the old table. + is_rehashing = false; + +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + if (old_table.data == local_data) { + // Everything is local, so no cleanup :P + } else +#endif + { + memdelete_arr(old_table.data); + memdelete_arr(old_table.keys); + memdelete_arr(old_table.hashes); + memdelete_arr(old_table.flags); + } + } + } + + // Table is almost full, resize and start rehashing process. + if (elements >= table.capacity * 0.7) { + + old_table.capacity = table.capacity; + old_table.data = table.data; + old_table.flags = table.flags; + old_table.hashes = table.hashes; + old_table.keys = table.keys; + + table.capacity = old_table.capacity * 2; + + table.data = memnew_arr(TData, table.capacity); + table.flags = memnew_arr(uint8_t, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0)); + table.hashes = memnew_arr(uint32_t, table.capacity); + table.keys = memnew_arr(TKey, table.capacity); + + zeromem(table.flags, table.capacity / 4 + (table.capacity % 4 != 0 ? 1 : 0)); + + is_rehashing = true; + rehash_position = 0; + rehash_amount = (elements * 2) / (table.capacity * 0.7 - old_table.capacity); + } + + if (!_raw_set_with_hash(hash, p_key, p_data)) + elements++; + } + + /** + * returns true if the value was found, false otherwise. + * + * if r_data is not NULL then the value will be written to the object + * it points to. + */ + bool lookup(const TKey &p_key, TData *r_data) { + + uint32_t hash = Hasher::hash(p_key); + + bool check_old_table = is_rehashing; + bool check_new_table = true; + + // search for the key and return the value associated with it + // + // if we're rehashing we need to check both the old and the + // current table. If we find a value in the old table we still + // need to continue searching in the new table as it might have + // been added after + + TData *value = NULL; + + for (int i = 0; i < table.capacity; i++) { + + if (!check_new_table && !check_old_table) { + + break; + } + + // if we're rehashing check the old table + if (check_old_table && i < old_table.capacity) { + + int pos = (hash + i) % old_table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) { + value = &old_table.data[pos]; + check_old_table = false; + } + } else if (!is_deleted_flag) { + + // we hit an empty field here, we don't + // need to further check this old table + // because we know it's not in here. + + check_old_table = false; + } + } + + if (check_new_table) { + + int pos = (hash + i) % table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) { + if (r_data != NULL) + *r_data = table.data[pos]; + return true; + } + continue; + } else if (is_deleted_flag) { + continue; + } else if (value != NULL) { + + // We found a value in the old table + if (r_data != NULL) + *r_data = *value; + return true; + } else { + check_new_table = false; + } + } + } + + if (value != NULL) { + if (r_data != NULL) + *r_data = *value; + return true; + } + return false; + } + + _FORCE_INLINE_ bool has(const TKey &p_key) { + return lookup(p_key, NULL); + } + + void remove(const TKey &p_key) { + uint32_t hash = Hasher::hash(p_key); + + bool check_old_table = is_rehashing; + bool check_new_table = true; + + for (int i = 0; i < table.capacity; i++) { + + if (!check_new_table && !check_old_table) { + return; + } + + // if we're rehashing check the old table + if (check_old_table && i < old_table.capacity) { + + int pos = (hash + i) % old_table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (old_table.hashes[pos] == hash && Comparator::compare(old_table.keys[pos], p_key)) { + old_table.keys[pos].~TKey(); + old_table.data[pos].~TData(); + + memnew_placement(&old_table.keys[pos], TKey); + memnew_placement(&old_table.data[pos], TData); + + old_table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); + old_table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); + + elements--; + return; + } + } else if (!is_deleted_flag) { + + // we hit an empty field here, we don't + // need to further check this old table + // because we know it's not in here. + + check_old_table = false; + } + } + + if (check_new_table) { + + int pos = (hash + i) % table.capacity; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + bool is_deleted_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset + 1))) > 0; + + if (is_filled_flag) { + // found our entry? + if (table.hashes[pos] == hash && Comparator::compare(table.keys[pos], p_key)) { + table.keys[pos].~TKey(); + table.data[pos].~TData(); + + memnew_placement(&table.keys[pos], TKey); + memnew_placement(&table.data[pos], TData); + + table.flags[flags_pos] &= ~(1 << (2 * flags_pos_offset)); + table.flags[flags_pos] |= (1 << (2 * flags_pos_offset + 1)); + + // don't return here, this value might still be in the old table + // if it was already relocated. + + elements--; + return; + } + continue; + } else if (is_deleted_flag) { + continue; + } else { + check_new_table = false; + } + } + } + } + + struct Iterator { + bool valid; + + uint32_t hash; + + const TKey *key; + const TData *data; + + private: + friend class OAHashMap; + bool was_from_old_table; + }; + + Iterator iter() const { + Iterator it; + + it.valid = false; + it.was_from_old_table = false; + + bool check_old_table = is_rehashing; + + for (int i = 0; i < table.capacity; i++) { + + // if we're rehashing check the old table first + if (check_old_table && i < old_table.capacity) { + + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = old_table.hashes[pos]; + it.data = &old_table.data[pos]; + it.key = &old_table.keys[pos]; + + it.was_from_old_table = true; + + return it; + } + } + + { + + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = table.hashes[pos]; + it.data = &table.data[pos]; + it.key = &table.keys[pos]; + + return it; + } + } + } + + return it; + } + + Iterator next_iter(const Iterator &p_iter) const { + if (!p_iter.valid) { + return p_iter; + } + + Iterator it; + + it.valid = false; + it.was_from_old_table = false; + + bool check_old_table = is_rehashing; + + // we use this to skip the first check or not + bool was_from_old_table = p_iter.was_from_old_table; + + int prev_index = (p_iter.data - (p_iter.was_from_old_table ? old_table.data : table.data)); + + if (!was_from_old_table) { + prev_index++; + } + + for (int i = prev_index; i < table.capacity; i++) { + + // if we're rehashing check the old table first + if (check_old_table && i < old_table.capacity && !was_from_old_table) { + + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (old_table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = old_table.hashes[pos]; + it.data = &old_table.data[pos]; + it.key = &old_table.keys[pos]; + + it.was_from_old_table = true; + + return it; + } + } + + was_from_old_table = false; + + { + int pos = i; + + int flags_pos = pos / 4; + int flags_pos_offset = pos % 4; + + bool is_filled_flag = (table.flags[flags_pos] & (1 << (2 * flags_pos_offset))) > 0; + + if (is_filled_flag) { + it.valid = true; + it.hash = table.hashes[pos]; + it.data = &table.data[pos]; + it.key = &table.keys[pos]; + + return it; + } + } + } + + return it; + } + + OAHashMap(uint32_t p_initial_capacity = INITIAL_NUM_ELEMENTS) { + +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + + if (p_initial_capacity <= INITIAL_NUM_ELEMENTS) { + table.data = local_data; + table.keys = local_keys; + table.hashes = local_hashes; + table.flags = local_flags; + + zeromem(table.flags, INITIAL_NUM_ELEMENTS / 4 + (INITIAL_NUM_ELEMENTS % 4 != 0 ? 1 : 0)); + + table.capacity = INITIAL_NUM_ELEMENTS; + elements = 0; + } else +#endif + { + table.data = memnew_arr(TData, p_initial_capacity); + table.keys = memnew_arr(TKey, p_initial_capacity); + table.hashes = memnew_arr(uint32_t, p_initial_capacity); + table.flags = memnew_arr(uint8_t, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0)); + + zeromem(table.flags, p_initial_capacity / 4 + (p_initial_capacity % 4 != 0 ? 1 : 0)); + + table.capacity = p_initial_capacity; + elements = 0; + } + + is_rehashing = false; + rehash_position = 0; + } + + ~OAHashMap() { +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + if (table.capacity <= INITIAL_NUM_ELEMENTS) { + return; // Everything is local, so no cleanup :P + } +#endif + if (is_rehashing) { + +#ifdef OA_HASH_MAP_INITIAL_LOCAL_STORAGE + if (old_table.data == local_data) { + // Everything is local, so no cleanup :P + } else +#endif + { + memdelete_arr(old_table.data); + memdelete_arr(old_table.keys); + memdelete_arr(old_table.hashes); + memdelete_arr(old_table.flags); + } + } + + memdelete_arr(table.data); + memdelete_arr(table.keys); + memdelete_arr(table.hashes); + memdelete_arr(table.flags); + } +}; + +#endif diff --git a/core/object.cpp b/core/object.cpp index 23e32a214a..b1770f1d7a 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -277,32 +277,32 @@ MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyIn MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name) : name(p_name), flags(METHOD_FLAG_NORMAL), + return_val(p_ret), id(0) { - return_val = p_ret; } MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1) : name(p_name), + return_val(p_ret), flags(METHOD_FLAG_NORMAL), id(0) { - return_val = p_ret; arguments.push_back(p_param1); } MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : name(p_name), + return_val(p_ret), flags(METHOD_FLAG_NORMAL), id(0) { - return_val = p_ret; arguments.push_back(p_param1); arguments.push_back(p_param2); } MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : name(p_name), + return_val(p_ret), flags(METHOD_FLAG_NORMAL), id(0) { - return_val = p_ret; arguments.push_back(p_param1); arguments.push_back(p_param2); arguments.push_back(p_param3); @@ -310,9 +310,9 @@ MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const Pr MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : name(p_name), + return_val(p_ret), flags(METHOD_FLAG_NORMAL), id(0) { - return_val = p_ret; arguments.push_back(p_param1); arguments.push_back(p_param2); arguments.push_back(p_param3); @@ -321,9 +321,9 @@ MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const Pr MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : name(p_name), + return_val(p_ret), flags(METHOD_FLAG_NORMAL), id(0) { - return_val = p_ret; arguments.push_back(p_param1); arguments.push_back(p_param2); arguments.push_back(p_param3); diff --git a/core/object.h b/core/object.h index 644e2b8270..3070439138 100644 --- a/core/object.h +++ b/core/object.h @@ -148,6 +148,7 @@ struct PropertyInfo { hint(PROPERTY_HINT_NONE), usage(PROPERTY_USAGE_DEFAULT) { } + PropertyInfo(Variant::Type p_type, const String p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) : type(p_type), name(p_name), @@ -161,12 +162,12 @@ struct PropertyInfo { class_name = p_class_name; } } + PropertyInfo(const StringName &p_class_name) : type(Variant::OBJECT), + class_name(p_class_name), hint(PROPERTY_HINT_NONE), usage(PROPERTY_USAGE_DEFAULT) { - - class_name = p_class_name; } bool operator<(const PropertyInfo &p_info) const { diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp index f24d6d16ca..1437e7cdfc 100644 --- a/core/os/dir_access.cpp +++ b/core/os/dir_access.cpp @@ -292,7 +292,7 @@ String DirAccess::get_full_path(const String &p_path, AccessType p_access) { return full; } -Error DirAccess::copy(String p_from, String p_to) { +Error DirAccess::copy(String p_from, String p_to, int chmod_flags) { //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); Error err; @@ -329,6 +329,11 @@ Error DirAccess::copy(String p_from, String p_to) { fdst->store_8(fsrc->get_8()); } + if (err == OK && chmod_flags != -1) { + fdst->close(); + err = fdst->_chmod(p_to, chmod_flags); + } + memdelete(fsrc); memdelete(fdst); diff --git a/core/os/dir_access.h b/core/os/dir_access.h index 6ad8b4c49b..7fa3ce5cf1 100644 --- a/core/os/dir_access.h +++ b/core/os/dir_access.h @@ -89,7 +89,7 @@ public: static bool exists(String p_dir); virtual size_t get_space_left() = 0; - virtual Error copy(String p_from, String p_to); + virtual Error copy(String p_from, String p_to, int chmod_flags = -1); virtual Error rename(String p_from, String p_to) = 0; virtual Error remove(String p_name) = 0; diff --git a/core/os/file_access.h b/core/os/file_access.h index 8393f0530b..63692cb290 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -140,6 +140,8 @@ public: virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType + virtual Error _chmod(const String &p_path, int p_mod) { return FAILED; } + static FileAccess *create(AccessType p_access); /// Create a file access (for the current platform) this is the only portable way of accessing files. static FileAccess *create_for_path(const String &p_path); static FileAccess *open(const String &p_path, int p_mode_flags, Error *r_error = NULL); /// Create a file access (for the current platform) this is the only portable way of accessing files. @@ -174,6 +176,7 @@ struct FileAccessRef { operator bool() const { return f != NULL; } FileAccess *f; + operator FileAccess *() { return f; } FileAccessRef(FileAccess *fa) { f = fa; } ~FileAccessRef() { if (f) memdelete(f); diff --git a/core/os/os.cpp b/core/os/os.cpp index 764f7fe6e6..437ce01a5e 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -485,7 +485,7 @@ bool OS::is_vsync_enabled() const { return true; } -PowerState OS::get_power_state() { +OS::PowerState OS::get_power_state() { return POWERSTATE_UNKNOWN; } int OS::get_power_seconds_left() { diff --git a/core/os/os.h b/core/os/os.h index 258708eea2..2fc87e44a0 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -34,7 +34,6 @@ #include "image.h" #include "list.h" #include "os/main_loop.h" -#include "power.h" #include "ustring.h" #include "vector.h" #include <stdarg.h> @@ -65,6 +64,14 @@ class OS { public: typedef void (*ImeCallback)(void *p_inp, String p_text, Point2 p_selection); + enum PowerState { + POWERSTATE_UNKNOWN, /**< cannot determine power status */ + POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */ + POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */ + POWERSTATE_CHARGING, /**< Plugged in, charging battery */ + POWERSTATE_CHARGED /**< Plugged in, battery charged */ + }; + enum RenderThreadMode { RENDER_THREAD_UNSAFE, @@ -279,6 +286,9 @@ public: bool is_stdout_verbose() const; + virtual void disable_crash_handler() {} + virtual bool is_disable_crash_handler() const { return false; } + enum CursorShape { CURSOR_ARROW, CURSOR_IBEAM, @@ -410,7 +420,7 @@ public: virtual void set_use_vsync(bool p_enable); virtual bool is_vsync_enabled() const; - virtual PowerState get_power_state(); + virtual OS::PowerState get_power_state(); virtual int get_power_seconds_left(); virtual int get_power_percent_left(); @@ -428,6 +438,6 @@ public: virtual ~OS(); }; -VARIANT_ENUM_CAST(PowerState); +VARIANT_ENUM_CAST(OS::PowerState); #endif diff --git a/core/os/power.h b/core/os/power.h deleted file mode 100644 index 59a091012e..0000000000 --- a/core/os/power.h +++ /dev/null @@ -1,42 +0,0 @@ -/*************************************************************************/ -/* power.h */ -/*************************************************************************/ -/* 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. */ -/*************************************************************************/ - -#ifndef CORE_OS_POWER_H_ -#define CORE_OS_POWER_H_ - -typedef enum { - POWERSTATE_UNKNOWN, /**< cannot determine power status */ - POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */ - POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */ - POWERSTATE_CHARGING, /**< Plugged in, charging battery */ - POWERSTATE_CHARGED /**< Plugged in, battery charged */ -} PowerState; - -#endif /* CORE_OS_POWER_H_ */ diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 23e4961138..7ea0d563a6 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -270,6 +270,11 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) { if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { _load_settings("res://override.cfg"); +#ifdef DEBUG_ENABLED + } else { + // when debug version of godot is used, provide some feedback to the developer + print_line("Couldn't open project over network"); +#endif } return OK; @@ -287,6 +292,12 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) { if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { //load override from location of the main pack _load_settings(p_main_pack.get_base_dir().plus_file("override.cfg")); +#ifdef DEBUG_ENABLED + // when debug version of godot is used, provide some feedback to the developer + print_line("Successfully loaded " + p_main_pack + "/project.godot or project.binary"); + } else { + print_line("Couldn't load/find " + p_main_pack + "/project.godot or project.binary"); +#endif } return OK; @@ -294,12 +305,43 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) { //Attempt with execname.pck if (exec_path != "") { + bool found = false; + + // get our filename without our path (note, using exec_path.get_file before get_basename anymore because not all file systems have dots in their file names!) + String filebase_name = exec_path.get_file().get_basename(); - if (_load_resource_pack(exec_path.get_basename() + ".pck")) { + // try to open at the location of executable + String datapack_name = exec_path.get_base_dir().plus_file(filebase_name) + ".pck"; + if (_load_resource_pack(datapack_name)) { + found = true; + } else { +#ifdef DEBUG_ENABLED + // when debug version of godot is used, provide some feedback to the developer + print_line("Couldn't open " + datapack_name); +#endif + datapack_name = filebase_name + ".pck"; + if (_load_resource_pack(datapack_name)) { + found = true; +#ifdef DEBUG_ENABLED + } else { + // when debug version of godot is used, provide some feedback to the developer + print_line("Couldn't open " + datapack_name); +#endif + } + } + // if we opened our package, try and load our project... + if (found) { if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { - //load override from location of executable + // load override from location of executable _load_settings(exec_path.get_base_dir().plus_file("override.cfg")); + +#ifdef DEBUG_ENABLED + // when debug version of godot is used, provide some feedback to the developer + print_line("Successfully loaded " + datapack_name + "/project.godot or project.binary"); + } else { + print_line("Couldn't load/find " + datapack_name + "/project.godot or project.binary"); +#endif } return OK; @@ -320,6 +362,12 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) { if (_load_settings("res://project.godot") == OK || _load_settings_binary("res://project.binary") == OK) { _load_settings("res://override.cfg"); +#ifdef DEBUG_ENABLED + // when debug version of godot is used, provide some feedback to the developer + print_line("Successfully loaded " + resource_path + "/project.godot or project.binary"); + } else { + print_line("Couldn't load/find " + resource_path + "/project.godot or project.binary"); +#endif } return OK; @@ -345,6 +393,12 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack) { candidate = current_dir; found = true; break; +#ifdef DEBUG_ENABLED + // when debug version of godot is used, provide some feedback to the developer + print_line("Successfully loaded " + current_dir + "/project.godot or project.binary"); + } else { + print_line("Couldn't load/find " + current_dir + "/project.godot or project.binary"); +#endif } d->change_dir(".."); diff --git a/core/reference.cpp b/core/reference.cpp index bb70628cbe..7f93922d22 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -33,7 +33,7 @@ bool Reference::init_ref() { - if (refcount.ref()) { + if (reference()) { // this may fail in the scenario of two threads assigning the pointer for the FIRST TIME // at the same time, which is never likely to happen (would be crazy to do) @@ -41,7 +41,7 @@ bool Reference::init_ref() { if (refcount_init.get() > 0) { refcount_init.unref(); - refcount.unref(); // first referencing is already 1, so compensate for the ref above + unreference(); // first referencing is already 1, so compensate for the ref above } return true; @@ -62,13 +62,16 @@ int Reference::reference_get_count() const { return refcount.get(); } -void Reference::reference() { +bool Reference::reference() { + bool success = refcount.ref(); - refcount.ref(); - if (get_script_instance()) { + if (success && get_script_instance()) { get_script_instance()->refcount_incremented(); } + + return success; } + bool Reference::unreference() { bool die = refcount.unref(); diff --git a/core/reference.h b/core/reference.h index ca3ae60418..bafc164276 100644 --- a/core/reference.h +++ b/core/reference.h @@ -51,7 +51,7 @@ protected: public: _FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() < 1; } bool init_ref(); - void reference(); + bool reference(); // returns false if refcount is at zero and didn't get increased bool unreference(); int reference_get_count() const; diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 27c31127a4..0e34a3eea5 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -68,6 +68,7 @@ static _Engine *_engine = NULL; static _ClassDB *_classdb = NULL; static _Marshalls *_marshalls = NULL; static TranslationLoaderPO *resource_format_po = NULL; +static _JSON *_json = NULL; static IP *ip = NULL; @@ -162,6 +163,8 @@ void register_core_types() { ClassDB::register_class<AStar>(); ClassDB::register_class<EncodedObjectAsID>(); + ClassDB::register_class<JSONParseResult>(); + ip = IP::create(); _geometry = memnew(_Geometry); @@ -172,6 +175,7 @@ void register_core_types() { _engine = memnew(_Engine); _classdb = memnew(_ClassDB); _marshalls = memnew(_Marshalls); + _json = memnew(_JSON); } void register_core_settings() { @@ -193,6 +197,7 @@ void register_core_singletons() { ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("TranslationServer", TranslationServer::get_singleton())); ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("Input", Input::get_singleton())); ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("InputMap", InputMap::get_singleton())); + ProjectSettings::get_singleton()->add_singleton(ProjectSettings::Singleton("JSON", _JSON::get_singleton())); } void unregister_core_types() { @@ -203,6 +208,7 @@ void unregister_core_types() { memdelete(_engine); memdelete(_classdb); memdelete(_marshalls); + memdelete(_json); memdelete(_geometry); diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 8875732b8e..f0097054b1 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -125,6 +125,9 @@ void ScriptDebuggerRemote::_put_variable(const String &p_name, const Variant &p_ packet_peer_stream->put_var(p_name); int len = 0; Error err = encode_variant(p_variable, NULL, len); + if (err != OK) + ERR_PRINT("Failed to encode variant"); + if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size packet_peer_stream->put_var(Variant()); } else { diff --git a/core/script_language.cpp b/core/script_language.cpp index bde80a30bc..5ead91f26e 100644 --- a/core/script_language.cpp +++ b/core/script_language.cpp @@ -184,7 +184,6 @@ void ScriptInstance::call_multilevel(const StringName &p_method, VARIANT_ARG_DEC argc++; } - Variant::CallError error; call_multilevel(p_method, argptr, argc); } diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp index 4760047959..27fc73ec63 100644 --- a/core/undo_redo.cpp +++ b/core/undo_redo.cpp @@ -503,6 +503,10 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_history"), &UndoRedo::clear_history); ClassDB::bind_method(D_METHOD("get_current_action_name"), &UndoRedo::get_current_action_name); ClassDB::bind_method(D_METHOD("get_version"), &UndoRedo::get_version); + ClassDB::bind_method(D_METHOD("set_max_steps", "max_steps"), &UndoRedo::set_max_steps); + ClassDB::bind_method(D_METHOD("get_max_steps"), &UndoRedo::get_max_steps); + ClassDB::bind_method(D_METHOD("redo"), &UndoRedo::redo); + ClassDB::bind_method(D_METHOD("undo"), &UndoRedo::undo); BIND_ENUM_CONSTANT(MERGE_DISABLE); BIND_ENUM_CONSTANT(MERGE_ENDS); diff --git a/core/variant.cpp b/core/variant.cpp index 74f6b6a711..52bdd4e22d 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -903,9 +903,6 @@ bool Variant::is_one() const { void Variant::reference(const Variant &p_variant) { - if (this == &p_variant) - return; - clear(); type = p_variant.type; @@ -924,17 +921,14 @@ void Variant::reference(const Variant &p_variant) { case INT: { _data._int = p_variant._data._int; - } break; case REAL: { _data._real = p_variant._data._real; - } break; case STRING: { memnew_placement(_data._mem, String(*reinterpret_cast<const String *>(p_variant._data._mem))); - } break; // math types @@ -942,33 +936,24 @@ void Variant::reference(const Variant &p_variant) { case VECTOR2: { memnew_placement(_data._mem, Vector2(*reinterpret_cast<const Vector2 *>(p_variant._data._mem))); - } break; case RECT2: { memnew_placement(_data._mem, Rect2(*reinterpret_cast<const Rect2 *>(p_variant._data._mem))); - } break; case TRANSFORM2D: { _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); - } break; case VECTOR3: { memnew_placement(_data._mem, Vector3(*reinterpret_cast<const Vector3 *>(p_variant._data._mem))); - } break; case PLANE: { memnew_placement(_data._mem, Plane(*reinterpret_cast<const Plane *>(p_variant._data._mem))); - } break; - /* - case QUAT: { - - } break;*/ case RECT3: { _data._rect3 = memnew(Rect3(*p_variant._data._rect3)); @@ -986,7 +971,6 @@ void Variant::reference(const Variant &p_variant) { case TRANSFORM: { _data._transform = memnew(Transform(*p_variant._data._transform)); - } break; // misc types @@ -1058,6 +1042,7 @@ void Variant::reference(const Variant &p_variant) { default: {} } } + void Variant::zero() { switch (type) { case NIL: break; @@ -1073,6 +1058,7 @@ void Variant::zero() { default: this->clear(); break; } } + void Variant::clear() { switch (type) { @@ -1092,12 +1078,10 @@ void Variant::clear() { case TRANSFORM2D: { memdelete(_data._transform2d); - } break; case RECT3: { memdelete(_data._rect3); - } break; case BASIS: { @@ -1106,14 +1090,12 @@ void Variant::clear() { case TRANSFORM: { memdelete(_data._transform); - } break; // misc types case NODE_PATH: { reinterpret_cast<NodePath *>(_data._mem)->~NodePath(); - } break; case OBJECT: { @@ -1127,48 +1109,39 @@ void Variant::clear() { case DICTIONARY: { reinterpret_cast<Dictionary *>(_data._mem)->~Dictionary(); - } break; case ARRAY: { reinterpret_cast<Array *>(_data._mem)->~Array(); - } break; // arrays case POOL_BYTE_ARRAY: { reinterpret_cast<PoolVector<uint8_t> *>(_data._mem)->~PoolVector<uint8_t>(); - } break; case POOL_INT_ARRAY: { reinterpret_cast<PoolVector<int> *>(_data._mem)->~PoolVector<int>(); - } break; case POOL_REAL_ARRAY: { reinterpret_cast<PoolVector<real_t> *>(_data._mem)->~PoolVector<real_t>(); - } break; case POOL_STRING_ARRAY: { reinterpret_cast<PoolVector<String> *>(_data._mem)->~PoolVector<String>(); - } break; case POOL_VECTOR2_ARRAY: { reinterpret_cast<PoolVector<Vector2> *>(_data._mem)->~PoolVector<Vector2>(); - } break; case POOL_VECTOR3_ARRAY: { reinterpret_cast<PoolVector<Vector3> *>(_data._mem)->~PoolVector<Vector3>(); - } break; case POOL_COLOR_ARRAY: { reinterpret_cast<PoolVector<Color> *>(_data._mem)->~PoolVector<Color>(); - } break; default: {} /* not needed */ } @@ -2259,8 +2232,8 @@ Variant::Variant(const RefPtr &p_resource) { type = OBJECT; memnew_placement(_data._mem, ObjData); - REF ref = p_resource; - _get_obj().obj = ref.ptr(); + REF *ref = reinterpret_cast<REF *>(p_resource.get_data()); + _get_obj().obj = ref->ptr(); _get_obj().ref = p_resource; } @@ -2496,7 +2469,135 @@ Variant::Variant(const Vector<Color> &p_array) { void Variant::operator=(const Variant &p_variant) { - reference(p_variant); + if (this == &p_variant) + return; + + if (type != p_variant.type) { + reference(p_variant); + return; + } + + switch (p_variant.type) { + case NIL: { + + // none + } break; + + // atomic types + case BOOL: { + + _data._bool = p_variant._data._bool; + } break; + case INT: { + + _data._int = p_variant._data._int; + } break; + case REAL: { + + _data._real = p_variant._data._real; + } break; + case STRING: { + + *reinterpret_cast<String *>(_data._mem) = *reinterpret_cast<const String *>(p_variant._data._mem); + } break; + + // math types + + case VECTOR2: { + + *reinterpret_cast<Vector2 *>(_data._mem) = *reinterpret_cast<const Vector2 *>(p_variant._data._mem); + } break; + case RECT2: { + + *reinterpret_cast<Rect2 *>(_data._mem) = *reinterpret_cast<const Rect2 *>(p_variant._data._mem); + } break; + case TRANSFORM2D: { + + *_data._transform2d = *(p_variant._data._transform2d); + } break; + case VECTOR3: { + + *reinterpret_cast<Vector3 *>(_data._mem) = *reinterpret_cast<const Vector3 *>(p_variant._data._mem); + } break; + case PLANE: { + + *reinterpret_cast<Plane *>(_data._mem) = *reinterpret_cast<const Plane *>(p_variant._data._mem); + } break; + + case RECT3: { + + *_data._rect3 = *(p_variant._data._rect3); + } break; + case QUAT: { + + *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem); + } break; + case BASIS: { + + *_data._basis = *(p_variant._data._basis); + } break; + case TRANSFORM: { + + *_data._transform = *(p_variant._data._transform); + } break; + + // misc types + case COLOR: { + + *reinterpret_cast<Color *>(_data._mem) = *reinterpret_cast<const Color *>(p_variant._data._mem); + } break; + case _RID: { + + *reinterpret_cast<RID *>(_data._mem) = *reinterpret_cast<const RID *>(p_variant._data._mem); + } break; + case OBJECT: { + + *reinterpret_cast<ObjData *>(_data._mem) = p_variant._get_obj(); + } break; + case NODE_PATH: { + + *reinterpret_cast<NodePath *>(_data._mem) = *reinterpret_cast<const NodePath *>(p_variant._data._mem); + } break; + case DICTIONARY: { + + *reinterpret_cast<Dictionary *>(_data._mem) = *reinterpret_cast<const Dictionary *>(p_variant._data._mem); + } break; + case ARRAY: { + + *reinterpret_cast<Array *>(_data._mem) = *reinterpret_cast<const Array *>(p_variant._data._mem); + } break; + + // arrays + case POOL_BYTE_ARRAY: { + + *reinterpret_cast<PoolVector<uint8_t> *>(_data._mem) = *reinterpret_cast<const PoolVector<uint8_t> *>(p_variant._data._mem); + } break; + case POOL_INT_ARRAY: { + + *reinterpret_cast<PoolVector<int> *>(_data._mem) = *reinterpret_cast<const PoolVector<int> *>(p_variant._data._mem); + } break; + case POOL_REAL_ARRAY: { + + *reinterpret_cast<PoolVector<real_t> *>(_data._mem) = *reinterpret_cast<const PoolVector<real_t> *>(p_variant._data._mem); + } break; + case POOL_STRING_ARRAY: { + + *reinterpret_cast<PoolVector<String> *>(_data._mem) = *reinterpret_cast<const PoolVector<String> *>(p_variant._data._mem); + } break; + case POOL_VECTOR2_ARRAY: { + + *reinterpret_cast<PoolVector<Vector2> *>(_data._mem) = *reinterpret_cast<const PoolVector<Vector2> *>(p_variant._data._mem); + } break; + case POOL_VECTOR3_ARRAY: { + + *reinterpret_cast<PoolVector<Vector3> *>(_data._mem) = *reinterpret_cast<const PoolVector<Vector3> *>(p_variant._data._mem); + } break; + case POOL_COLOR_ARRAY: { + + *reinterpret_cast<PoolVector<Color> *>(_data._mem) = *reinterpret_cast<const PoolVector<Color> *>(p_variant._data._mem); + } break; + default: {} + } } Variant::Variant(const IP_Address &p_address) { diff --git a/core/variant.h b/core/variant.h index c44608ebfa..5ea540a63f 100644 --- a/core/variant.h +++ b/core/variant.h @@ -43,7 +43,6 @@ #include "math_2d.h" #include "matrix3.h" #include "node_path.h" -#include "os/power.h" #include "plane.h" #include "quat.h" #include "rect3.h" @@ -71,6 +70,7 @@ typedef PoolVector<Color> PoolColorArray; class Variant { public: + // If this changes the table in variant_op must be updated enum Type { NIL, @@ -289,6 +289,7 @@ public: Variant(const IP_Address &p_address); + // If this changes the table in variant_op must be updated enum Operator { //comparation @@ -300,7 +301,7 @@ public: OP_GREATER_EQUAL, //mathematic OP_ADD, - OP_SUBSTRACT, + OP_SUBTRACT, OP_MULTIPLY, OP_DIVIDE, OP_NEGATE, @@ -389,7 +390,7 @@ public: uint32_t hash() const; bool hash_compare(const Variant &p_variant) const; - bool booleanize(bool &valid) const; + bool booleanize() const; void static_assign(const Variant &p_variant); static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index dc1c24d234..19d9b0297f 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -428,8 +428,8 @@ struct _VariantCall { VCALL_LOCALMEM2R(Quat, slerpni); VCALL_LOCALMEM4R(Quat, cubic_slerp); - VCALL_LOCALMEM0R(Color, to_32); - VCALL_LOCALMEM0R(Color, to_ARGB32); + VCALL_LOCALMEM0R(Color, to_rgba32); + VCALL_LOCALMEM0R(Color, to_argb32); VCALL_LOCALMEM0R(Color, gray); VCALL_LOCALMEM0R(Color, inverted); VCALL_LOCALMEM0R(Color, contrasted); @@ -1524,8 +1524,8 @@ void register_variant_methods() { ADDFUNC2(QUAT, QUAT, Quat, slerpni, QUAT, "b", REAL, "t", varray()); ADDFUNC4(QUAT, QUAT, Quat, cubic_slerp, QUAT, "b", QUAT, "pre_a", QUAT, "post_b", REAL, "t", varray()); - ADDFUNC0(COLOR, INT, Color, to_32, varray()); - ADDFUNC0(COLOR, INT, Color, to_ARGB32, varray()); + ADDFUNC0(COLOR, INT, Color, to_rgba32, varray()); + ADDFUNC0(COLOR, INT, Color, to_argb32, varray()); ADDFUNC0(COLOR, REAL, Color, gray, varray()); ADDFUNC0(COLOR, COLOR, Color, inverted, varray()); ADDFUNC0(COLOR, COLOR, Color, contrasted, varray()); @@ -1623,7 +1623,7 @@ void register_variant_methods() { ADDFUNC2(POOL_STRING_ARRAY, INT, PoolStringArray, insert, INT, "idx", STRING, "string", varray()); ADDFUNC1(POOL_STRING_ARRAY, NIL, PoolStringArray, resize, INT, "idx", varray()); ADDFUNC0(POOL_STRING_ARRAY, NIL, PoolStringArray, invert, varray()); - ADDFUNC1(POOL_STRING_ARRAY, STRING, PoolStringArray, join, STRING, "string", varray()); + ADDFUNC1(POOL_STRING_ARRAY, STRING, PoolStringArray, join, STRING, "delimiter", varray()); ADDFUNC0(POOL_VECTOR2_ARRAY, INT, PoolVector2Array, size, varray()); ADDFUNC2(POOL_VECTOR2_ARRAY, NIL, PoolVector2Array, set, INT, "idx", VECTOR2, "vector2", varray()); diff --git a/core/variant_op.cpp b/core/variant_op.cpp index b6e114b853..5d47936679 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -33,49 +33,123 @@ #include "object.h" #include "script_language.h" -Variant::operator bool() const { - - bool b; - return booleanize(b); +#define CASE_TYPE_ALL(PREFIX, OP) \ + CASE_TYPE(PREFIX, OP, INT) \ + CASE_TYPE_ALL_BUT_INT(PREFIX, OP) + +#define CASE_TYPE_ALL_BUT_INT(PREFIX, OP) \ + CASE_TYPE(PREFIX, OP, NIL) \ + CASE_TYPE(PREFIX, OP, BOOL) \ + CASE_TYPE(PREFIX, OP, REAL) \ + CASE_TYPE(PREFIX, OP, STRING) \ + CASE_TYPE(PREFIX, OP, VECTOR2) \ + CASE_TYPE(PREFIX, OP, RECT2) \ + CASE_TYPE(PREFIX, OP, VECTOR3) \ + CASE_TYPE(PREFIX, OP, TRANSFORM2D) \ + CASE_TYPE(PREFIX, OP, PLANE) \ + CASE_TYPE(PREFIX, OP, QUAT) \ + CASE_TYPE(PREFIX, OP, RECT3) \ + CASE_TYPE(PREFIX, OP, BASIS) \ + CASE_TYPE(PREFIX, OP, TRANSFORM) \ + CASE_TYPE(PREFIX, OP, COLOR) \ + CASE_TYPE(PREFIX, OP, NODE_PATH) \ + CASE_TYPE(PREFIX, OP, _RID) \ + CASE_TYPE(PREFIX, OP, OBJECT) \ + CASE_TYPE(PREFIX, OP, DICTIONARY) \ + CASE_TYPE(PREFIX, OP, ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_BYTE_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_INT_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_REAL_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_STRING_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR2_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR3_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_COLOR_ARRAY) + +#ifdef __GNUC__ +#define TYPE(PREFIX, OP, TYPE) &&PREFIX##_##OP##_##TYPE + +/* clang-format off */ +#define TYPES(PREFIX, OP) { \ + TYPE(PREFIX, OP, NIL), \ + TYPE(PREFIX, OP, BOOL), \ + TYPE(PREFIX, OP, INT), \ + TYPE(PREFIX, OP, REAL), \ + TYPE(PREFIX, OP, STRING), \ + TYPE(PREFIX, OP, VECTOR2), \ + TYPE(PREFIX, OP, RECT2), \ + TYPE(PREFIX, OP, VECTOR3), \ + TYPE(PREFIX, OP, TRANSFORM2D), \ + TYPE(PREFIX, OP, PLANE), \ + TYPE(PREFIX, OP, QUAT), \ + TYPE(PREFIX, OP, RECT3), \ + TYPE(PREFIX, OP, BASIS), \ + TYPE(PREFIX, OP, TRANSFORM), \ + TYPE(PREFIX, OP, COLOR), \ + TYPE(PREFIX, OP, NODE_PATH), \ + TYPE(PREFIX, OP, _RID), \ + TYPE(PREFIX, OP, OBJECT), \ + TYPE(PREFIX, OP, DICTIONARY), \ + TYPE(PREFIX, OP, ARRAY), \ + TYPE(PREFIX, OP, POOL_BYTE_ARRAY), \ + TYPE(PREFIX, OP, POOL_INT_ARRAY), \ + TYPE(PREFIX, OP, POOL_REAL_ARRAY), \ + TYPE(PREFIX, OP, POOL_STRING_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR2_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR3_ARRAY), \ + TYPE(PREFIX, OP, POOL_COLOR_ARRAY), \ +} +/* clang-format on */ + +#define CASES(PREFIX) static void *switch_table_##PREFIX[25][27] = { \ + TYPES(PREFIX, OP_EQUAL), \ + TYPES(PREFIX, OP_NOT_EQUAL), \ + TYPES(PREFIX, OP_LESS), \ + TYPES(PREFIX, OP_LESS_EQUAL), \ + TYPES(PREFIX, OP_GREATER), \ + TYPES(PREFIX, OP_GREATER_EQUAL), \ + TYPES(PREFIX, OP_ADD), \ + TYPES(PREFIX, OP_SUBTRACT), \ + TYPES(PREFIX, OP_MULTIPLY), \ + TYPES(PREFIX, OP_DIVIDE), \ + TYPES(PREFIX, OP_NEGATE), \ + TYPES(PREFIX, OP_POSITIVE), \ + TYPES(PREFIX, OP_MODULE), \ + TYPES(PREFIX, OP_STRING_CONCAT), \ + TYPES(PREFIX, OP_SHIFT_LEFT), \ + TYPES(PREFIX, OP_SHIFT_RIGHT), \ + TYPES(PREFIX, OP_BIT_AND), \ + TYPES(PREFIX, OP_BIT_OR), \ + TYPES(PREFIX, OP_BIT_XOR), \ + TYPES(PREFIX, OP_BIT_NEGATE), \ + TYPES(PREFIX, OP_AND), \ + TYPES(PREFIX, OP_OR), \ + TYPES(PREFIX, OP_XOR), \ + TYPES(PREFIX, OP_NOT), \ + TYPES(PREFIX, OP_IN), \ } -bool Variant::booleanize(bool &r_valid) const { +#define SWITCH(PREFIX, op, val) goto *switch_table_##PREFIX[op][val]; +#define SWITCH_OP(PREFIX, OP, val) +#define CASE_TYPE(PREFIX, OP, TYPE) PREFIX##_##OP##_##TYPE: + +#else +#define CASES(PREFIX) +#define SWITCH(PREFIX, op, val) switch (op) +#define SWITCH_OP(PREFIX, OP, val) \ + case OP: \ + switch (val) +#define CASE_TYPE(PREFIX, OP, TYPE) case TYPE: +#endif - r_valid = true; - switch (type) { - case NIL: return false; - case BOOL: return _data._bool; - case INT: return _data._int; - case REAL: return _data._real; - case STRING: return (*reinterpret_cast<const String *>(_data._mem)) != ""; - case VECTOR2: - case RECT2: - case TRANSFORM2D: - case VECTOR3: - case PLANE: - case RECT3: - case QUAT: - case BASIS: - case TRANSFORM: - case COLOR: - case _RID: return (*reinterpret_cast<const RID *>(_data._mem)).is_valid(); - case OBJECT: return _get_obj().obj; - case NODE_PATH: return (*reinterpret_cast<const NodePath *>(_data._mem)) != NodePath(); - case DICTIONARY: - case ARRAY: - case POOL_BYTE_ARRAY: - case POOL_INT_ARRAY: - case POOL_REAL_ARRAY: - case POOL_STRING_ARRAY: - case POOL_VECTOR2_ARRAY: - case POOL_VECTOR3_ARRAY: - case POOL_COLOR_ARRAY: - r_valid = false; - return false; - default: {} - } +Variant::operator bool() const { - return false; + return booleanize(); +} + +// We consider all unitialized or empty types to be false based on the type's +// zeroiness. +bool Variant::booleanize() const { + return !is_zero(); } #define _RETURN(m_what) \ @@ -84,10 +158,15 @@ bool Variant::booleanize(bool &r_valid) const { return; \ } -#define DEFAULT_OP_NUM(m_op, m_name, m_type) \ - case m_name: { \ +#define _RETURN_FAIL \ + { \ + r_valid = false; \ + return; \ + } + +#define DEFAULT_OP_NUM(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ switch (p_b.type) { \ - case BOOL: _RETURN(p_a._data.m_type m_op p_b._data._bool); \ case INT: _RETURN(p_a._data.m_type m_op p_b._data._int); \ case REAL: _RETURN(p_a._data.m_type m_op p_b._data._real); \ default: {} \ @@ -96,22 +175,55 @@ bool Variant::booleanize(bool &r_valid) const { return; \ }; -#define DEFAULT_OP_NUM_NEG(m_name, m_type) \ - case m_name: { \ - \ - _RETURN(-p_a._data.m_type); \ +#ifdef DEBUG_ENABLED +#define DEFAULT_OP_NUM_DIV(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + switch (p_b.type) { \ + case INT: { \ + if (p_b._data._int == 0) { \ + r_valid = false; \ + _RETURN("Division By Zero"); \ + } \ + _RETURN(p_a._data.m_type / p_b._data._int); \ + } \ + case REAL: { \ + if (p_b._data._real == 0) { \ + r_valid = false; \ + _RETURN("Division By Zero"); \ + } \ + _RETURN(p_a._data.m_type / p_b._data._real); \ + } \ + default: {} \ + } \ + r_valid = false; \ + return; \ + }; +#else +#define DEFAULT_OP_NUM_DIV(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + switch (p_b.type) { \ + case INT: _RETURN(p_a._data.m_type / p_b._data._int); \ + case REAL: _RETURN(p_a._data.m_type / p_b._data._real); \ + default: {} \ + } \ + r_valid = false; \ + return; \ }; +#endif -#define DEFAULT_OP_NUM_POS(m_name, m_type) \ - case m_name: { \ - \ - _RETURN(p_a._data.m_type); \ +#define DEFAULT_OP_NUM_NEG(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + _RETURN(-p_a._data.m_type); \ }; -#define DEFAULT_OP_NUM_VEC(m_op, m_name, m_type) \ - case m_name: { \ +#define DEFAULT_OP_NUM_POS(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + _RETURN(p_a._data.m_type); \ + }; + +#define DEFAULT_OP_NUM_VEC(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ switch (p_b.type) { \ - case BOOL: _RETURN(p_a._data.m_type m_op p_b._data._bool); \ case INT: _RETURN(p_a._data.m_type m_op p_b._data._int); \ case REAL: _RETURN(p_a._data.m_type m_op p_b._data._real); \ case VECTOR2: _RETURN(p_a._data.m_type m_op *reinterpret_cast<const Vector2 *>(p_b._data._mem)); \ @@ -122,8 +234,19 @@ bool Variant::booleanize(bool &r_valid) const { return; \ }; -#define DEFAULT_OP_STR(m_op, m_name, m_type) \ - case m_name: { \ +#define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + switch (p_b.type) { \ + case STRING: _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const String *>(p_a._data._mem)); \ + case NODE_PATH: _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const NodePath *>(p_a._data._mem)); \ + default: {} \ + } \ + r_valid = false; \ + return; \ + }; + +#define DEFAULT_OP_STR(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ switch (p_b.type) { \ case STRING: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const String *>(p_b._data._mem)); \ case NODE_PATH: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const NodePath *>(p_b._data._mem)); \ @@ -133,31 +256,36 @@ bool Variant::booleanize(bool &r_valid) const { return; \ }; -#define DEFAULT_OP_LOCALMEM(m_op, m_name, m_type) \ - case m_name: { \ - switch (p_b.type) { \ - case m_name: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \ - default: {} \ - } \ - r_valid = false; \ - return; \ - } +#define DEFAULT_OP_LOCALMEM_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == m_name) \ + _RETURN(*reinterpret_cast<const m_type *>(p_b._data._mem) m_op *reinterpret_cast<const m_type *>(p_a._data._mem)); \ + r_valid = false; \ + return; \ + }; + +#define DEFAULT_OP_LOCALMEM(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == m_name) \ + _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \ + r_valid = false; \ + return; \ + }; -#define DEFAULT_OP_LOCALMEM_NEG(m_name, m_type) \ - case m_name: { \ +#define DEFAULT_OP_LOCALMEM_NEG(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ _RETURN(-*reinterpret_cast<const m_type *>(p_a._data._mem)); \ } -#define DEFAULT_OP_LOCALMEM_POS(m_name, m_type) \ - case m_name: { \ - _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem)); \ +#define DEFAULT_OP_LOCALMEM_POS(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem)); \ } -#define DEFAULT_OP_LOCALMEM_NUM(m_op, m_name, m_type) \ - case m_name: { \ +#define DEFAULT_OP_LOCALMEM_NUM(m_prefix, m_op_name, m_name, m_op, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ switch (p_b.type) { \ case m_name: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op *reinterpret_cast<const m_type *>(p_b._data._mem)); \ - case BOOL: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op p_b._data._bool); \ case INT: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op p_b._data._int); \ case REAL: _RETURN(*reinterpret_cast<const m_type *>(p_a._data._mem) m_op p_b._data._real); \ default: {} \ @@ -176,50 +304,51 @@ bool Variant::booleanize(bool &r_valid) const { return; \ } -#define DEFAULT_OP_PTRREF(m_op, m_name, m_sub) \ - case m_name: { \ - switch (p_b.type) { \ - case m_name: _RETURN(*p_a._data.m_sub m_op *p_b._data.m_sub); \ - default: {} \ - } \ - r_valid = false; \ - return; \ +#define DEFAULT_OP_PTRREF(m_prefix, m_op_name, m_name, m_op, m_sub) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_b.type == m_name) \ + _RETURN(*p_a._data.m_sub m_op *p_b._data.m_sub); \ + r_valid = false; \ + return; \ } -#define DEFAULT_OP_ARRAY_EQ(m_name, m_type) \ - DEFAULT_OP_ARRAY_OP(m_name, m_type, !=, !=, true, false, false) - -#define DEFAULT_OP_ARRAY_LT(m_name, m_type) \ - DEFAULT_OP_ARRAY_OP(m_name, m_type, <, !=, false, a_len < array_b.size(), true) - -#define DEFAULT_OP_ARRAY_OP(m_name, m_type, m_opa, m_opb, m_ret_def, m_ret_s, m_ret_f) \ - case m_name: { \ - if (p_a.type != p_b.type) { \ - r_valid = false; \ - return; \ - } \ - const PoolVector<m_type> &array_a = *reinterpret_cast<const PoolVector<m_type> *>(p_a._data._mem); \ - const PoolVector<m_type> &array_b = *reinterpret_cast<const PoolVector<m_type> *>(p_b._data._mem); \ - \ - int a_len = array_a.size(); \ - if (a_len m_opa array_b.size()) { \ - _RETURN(m_ret_s); \ - } else { \ - \ - PoolVector<m_type>::Read ra = array_a.read(); \ - PoolVector<m_type>::Read rb = array_b.read(); \ - \ - for (int i = 0; i < a_len; i++) { \ - if (ra[i] m_opb rb[i]) \ - _RETURN(m_ret_f); \ - } \ - \ - _RETURN(m_ret_def); \ - } \ +#define DEFAULT_OP_ARRAY_EQ(m_prefix, m_op_name, m_name, m_type) \ + DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, !=, !=, true, false, false) + +#define DEFAULT_OP_ARRAY_LT(m_prefix, m_op_name, m_name, m_type) \ + DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, <, !=, false, a_len < array_b.size(), true) + +#define DEFAULT_OP_ARRAY_GT(m_prefix, m_op_name, m_name, m_type) \ + DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, >, !=, false, a_len < array_b.size(), true) + +#define DEFAULT_OP_ARRAY_OP(m_prefix, m_op_name, m_name, m_type, m_opa, m_opb, m_ret_def, m_ret_s, m_ret_f) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ + if (p_a.type != p_b.type) { \ + r_valid = false; \ + return; \ + } \ + const PoolVector<m_type> &array_a = *reinterpret_cast<const PoolVector<m_type> *>(p_a._data._mem); \ + const PoolVector<m_type> &array_b = *reinterpret_cast<const PoolVector<m_type> *>(p_b._data._mem); \ + \ + int a_len = array_a.size(); \ + if (a_len m_opa array_b.size()) { \ + _RETURN(m_ret_s); \ + } else { \ + \ + PoolVector<m_type>::Read ra = array_a.read(); \ + PoolVector<m_type>::Read rb = array_b.read(); \ + \ + for (int i = 0; i < a_len; i++) { \ + if (ra[i] m_opb rb[i]) \ + _RETURN(m_ret_f); \ + } \ + \ + _RETURN(m_ret_def); \ + } \ } -#define DEFAULT_OP_ARRAY_ADD(m_name, m_type) \ - case m_name: { \ +#define DEFAULT_OP_ARRAY_ADD(m_prefix, m_op_name, m_name, m_type) \ + CASE_TYPE(m_prefix, m_op_name, m_name) { \ if (p_a.type != p_b.type) { \ r_valid = false; \ _RETURN(NIL); \ @@ -231,595 +360,646 @@ bool Variant::booleanize(bool &r_valid) const { _RETURN(sum); \ } -#define DEFAULT_OP_FAIL(m_name) \ - case m_name: { \ - r_valid = false; \ - return; \ - } - -void Variant::evaluate(const Operator &p_op, const Variant &p_a, const Variant &p_b, Variant &r_ret, bool &r_valid) { +void Variant::evaluate(const Operator &p_op, const Variant &p_a, + const Variant &p_b, Variant &r_ret, bool &r_valid) { + CASES(math); r_valid = true; - switch (p_op) { + SWITCH(math, p_op, p_a.type) { + SWITCH_OP(math, OP_EQUAL, p_a.type) { + CASE_TYPE(math, OP_EQUAL, NIL) { + if (p_b.type == NIL) _RETURN(true); + if (p_b.type == OBJECT) + _RETURN(p_b._get_obj().obj == NULL); + _RETURN_FAIL; + } - case OP_EQUAL: { + CASE_TYPE(math, OP_EQUAL, BOOL) { + if (p_b.type != BOOL) + _RETURN_FAIL; + _RETURN(p_a._data._bool == p_b._data._bool); + } - if ((int(p_a.type) * int(p_b.type)) == 0) { - //null case is an exception, one of both is null - if (p_a.type == p_b.type) //null against null is true - _RETURN(true); - //only against object is allowed - if (p_a.type == Variant::OBJECT) { + CASE_TYPE(math, OP_EQUAL, OBJECT) { + if (p_b.type == OBJECT) + _RETURN((p_a._get_obj().obj == p_b._get_obj().obj)); + if (p_b.type == NIL) _RETURN(p_a._get_obj().obj == NULL); - } else if (p_b.type == Variant::OBJECT) { - _RETURN(p_b._get_obj().obj == NULL); - } - //otherwise, always false - _RETURN(false); + _RETURN_FAIL; } - switch (p_a.type) { + CASE_TYPE(math, OP_EQUAL, DICTIONARY) { + if (p_b.type != DICTIONARY) + _RETURN_FAIL; + + const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem); + const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem); + + _RETURN(*arr_a == *arr_b); + } - case NIL: { + CASE_TYPE(math, OP_EQUAL, ARRAY) { + if (p_b.type != ARRAY) + _RETURN_FAIL; - _RETURN(p_b.type == NIL || (p_b.type == Variant::OBJECT && !p_b._get_obj().obj)); - } break; + const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); + const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); - DEFAULT_OP_NUM(==, BOOL, _bool); - DEFAULT_OP_NUM(==, INT, _int); - DEFAULT_OP_NUM(==, REAL, _real); - DEFAULT_OP_STR(==, STRING, String); - DEFAULT_OP_LOCALMEM(==, VECTOR2, Vector2); - DEFAULT_OP_LOCALMEM(==, RECT2, Rect2); - DEFAULT_OP_PTRREF(==, TRANSFORM2D, _transform2d); - DEFAULT_OP_LOCALMEM(==, VECTOR3, Vector3); - DEFAULT_OP_LOCALMEM(==, PLANE, Plane); - DEFAULT_OP_LOCALMEM(==, QUAT, Quat); - DEFAULT_OP_PTRREF(==, RECT3, _rect3); - DEFAULT_OP_PTRREF(==, BASIS, _basis); - DEFAULT_OP_PTRREF(==, TRANSFORM, _transform); + int l = arr_a->size(); + if (arr_b->size() != l) + _RETURN(false); + for (int i = 0; i < l; i++) { + if (!((*arr_a)[i] == (*arr_b)[i])) { + _RETURN(false); + } + } - DEFAULT_OP_LOCALMEM(==, COLOR, Color); - DEFAULT_OP_STR(==, NODE_PATH, NodePath); - DEFAULT_OP_LOCALMEM(==, _RID, RID); - case OBJECT: { + _RETURN(true); + } + + DEFAULT_OP_NUM(math, OP_EQUAL, INT, ==, _int); + DEFAULT_OP_NUM(math, OP_EQUAL, REAL, ==, _real); + DEFAULT_OP_STR(math, OP_EQUAL, STRING, ==, String); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, VECTOR2, ==, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, RECT2, ==, Rect2); + DEFAULT_OP_PTRREF(math, OP_EQUAL, TRANSFORM2D, ==, _transform2d); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, VECTOR3, ==, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, PLANE, ==, Plane); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, QUAT, ==, Quat); + DEFAULT_OP_PTRREF(math, OP_EQUAL, RECT3, ==, _rect3); + DEFAULT_OP_PTRREF(math, OP_EQUAL, BASIS, ==, _basis); + DEFAULT_OP_PTRREF(math, OP_EQUAL, TRANSFORM, ==, _transform); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, COLOR, ==, Color); + DEFAULT_OP_STR(math, OP_EQUAL, NODE_PATH, ==, NodePath); + DEFAULT_OP_LOCALMEM(math, OP_EQUAL, _RID, ==, RID); + + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_BYTE_ARRAY, uint8_t); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_INT_ARRAY, int); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_REAL_ARRAY, real_t); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_COLOR_ARRAY, Color); + } - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj == p_b._get_obj().obj)); - if (p_b.type == NIL) - _RETURN(!p_a._get_obj().obj); - } break; + SWITCH_OP(math, OP_NOT_EQUAL, p_a.type) { + CASE_TYPE(math, OP_NOT_EQUAL, NIL) { + if (p_b.type == NIL) _RETURN(false); + if (p_b.type == OBJECT) + _RETURN(p_b._get_obj().obj != NULL); + _RETURN_FAIL; + } - case DICTIONARY: { + CASE_TYPE(math, OP_NOT_EQUAL, BOOL) { + if (p_b.type != BOOL) + _RETURN_FAIL; + _RETURN(p_a._data._bool != p_b._data._bool); + } - if (p_b.type != DICTIONARY) - _RETURN(false); + CASE_TYPE(math, OP_NOT_EQUAL, OBJECT) { + if (p_b.type == OBJECT) + _RETURN((p_a._get_obj().obj != p_b._get_obj().obj)); + if (p_b.type == NIL) + _RETURN(p_a._get_obj().obj != NULL); + _RETURN_FAIL; + } - const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem); - const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem); + CASE_TYPE(math, OP_NOT_EQUAL, DICTIONARY) { + if (p_b.type != DICTIONARY) + _RETURN_FAIL; - _RETURN(*arr_a == *arr_b); + const Dictionary *arr_a = reinterpret_cast<const Dictionary *>(p_a._data._mem); + const Dictionary *arr_b = reinterpret_cast<const Dictionary *>(p_b._data._mem); - } break; - case ARRAY: { + _RETURN((*arr_a == *arr_b) == false); + } - if (p_b.type != ARRAY) - _RETURN(false); + CASE_TYPE(math, OP_NOT_EQUAL, ARRAY) { + if (p_b.type != ARRAY) + _RETURN_FAIL; - const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); - const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); + const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); + const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); - int l = arr_a->size(); - if (arr_b->size() != l) + int l = arr_a->size(); + if (arr_b->size() != l) + _RETURN(true); + for (int i = 0; i < l; i++) { + if (((*arr_a)[i] == (*arr_b)[i])) { _RETURN(false); - for (int i = 0; i < l; i++) { - if (!((*arr_a)[i] == (*arr_b)[i])) { - _RETURN(false); - } } + } - _RETURN(true); + _RETURN(true); + } + + DEFAULT_OP_NUM(math, OP_NOT_EQUAL, INT, !=, _int); + DEFAULT_OP_NUM(math, OP_NOT_EQUAL, REAL, !=, _real); + DEFAULT_OP_STR(math, OP_NOT_EQUAL, STRING, !=, String); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, VECTOR2, !=, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, RECT2, !=, Rect2); + DEFAULT_OP_PTRREF(math, OP_NOT_EQUAL, TRANSFORM2D, !=, _transform2d); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, VECTOR3, !=, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, PLANE, !=, Plane); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, QUAT, !=, Quat); + DEFAULT_OP_PTRREF(math, OP_NOT_EQUAL, RECT3, !=, _rect3); + DEFAULT_OP_PTRREF(math, OP_NOT_EQUAL, BASIS, !=, _basis); + DEFAULT_OP_PTRREF(math, OP_NOT_EQUAL, TRANSFORM, !=, _transform); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, COLOR, !=, Color); + DEFAULT_OP_STR(math, OP_NOT_EQUAL, NODE_PATH, !=, NodePath); + DEFAULT_OP_LOCALMEM(math, OP_NOT_EQUAL, _RID, !=, RID); + + CASE_TYPE(math, OP_NOT_EQUAL, POOL_BYTE_ARRAY); + CASE_TYPE(math, OP_NOT_EQUAL, POOL_INT_ARRAY); + CASE_TYPE(math, OP_NOT_EQUAL, POOL_REAL_ARRAY); + CASE_TYPE(math, OP_NOT_EQUAL, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_NOT_EQUAL, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_NOT_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_NOT_EQUAL, POOL_COLOR_ARRAY); + _RETURN_FAIL; + } - } break; + SWITCH_OP(math, OP_LESS, p_a.type) { + CASE_TYPE(math, OP_LESS, BOOL) { + if (p_b.type != BOOL) + _RETURN_FAIL; - DEFAULT_OP_ARRAY_EQ(POOL_BYTE_ARRAY, uint8_t); - DEFAULT_OP_ARRAY_EQ(POOL_INT_ARRAY, int); - DEFAULT_OP_ARRAY_EQ(POOL_REAL_ARRAY, real_t); - DEFAULT_OP_ARRAY_EQ(POOL_STRING_ARRAY, String); - DEFAULT_OP_ARRAY_EQ(POOL_VECTOR2_ARRAY, Vector3); - DEFAULT_OP_ARRAY_EQ(POOL_VECTOR3_ARRAY, Vector3); - DEFAULT_OP_ARRAY_EQ(POOL_COLOR_ARRAY, Color); + if (p_a._data._bool == p_b._data._bool) + _RETURN(false); - case VARIANT_MAX: { - r_valid = false; - return; + if (p_a._data._bool && !p_b._data._bool) + _RETURN(false); - } break; + _RETURN(true); } - } break; - case OP_NOT_EQUAL: { - Variant res; - evaluate(OP_EQUAL, p_a, p_b, res, r_valid); - if (!r_valid) - return; - if (res.type == BOOL) - res._data._bool = !res._data._bool; - _RETURN(res); - - } break; - case OP_LESS: { - - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM(<, BOOL, _bool); - DEFAULT_OP_NUM(<, INT, _int); - DEFAULT_OP_NUM(<, REAL, _real); - DEFAULT_OP_STR(<, STRING, String); - DEFAULT_OP_LOCALMEM(<, VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_LOCALMEM(<, VECTOR3, Vector3); - DEFAULT_OP_FAIL(PLANE); - DEFAULT_OP_FAIL(QUAT); - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_LOCALMEM(<, _RID, RID); - case OBJECT: { - - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj < p_b._get_obj().obj)); - } break; - DEFAULT_OP_FAIL(DICTIONARY); - case ARRAY: { - - if (p_b.type != ARRAY) - _RETURN(false); - const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); - const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); - - int l = arr_a->size(); - if (arr_b->size() < l) - _RETURN(false); - for (int i = 0; i < l; i++) { - if (!((*arr_a)[i] < (*arr_b)[i])) { - _RETURN(true); - } - } + CASE_TYPE(math, OP_LESS, OBJECT) { + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj < p_b._get_obj().obj)); + } - _RETURN(false); + CASE_TYPE(math, OP_LESS, ARRAY) { + if (p_b.type != ARRAY) + _RETURN_FAIL; - } break; - DEFAULT_OP_ARRAY_LT(POOL_BYTE_ARRAY, uint8_t); - DEFAULT_OP_ARRAY_LT(POOL_INT_ARRAY, int); - DEFAULT_OP_ARRAY_LT(POOL_REAL_ARRAY, real_t); - DEFAULT_OP_ARRAY_LT(POOL_STRING_ARRAY, String); - DEFAULT_OP_ARRAY_LT(POOL_VECTOR2_ARRAY, Vector3); - DEFAULT_OP_ARRAY_LT(POOL_VECTOR3_ARRAY, Vector3); - DEFAULT_OP_ARRAY_LT(POOL_COLOR_ARRAY, Color); - case VARIANT_MAX: { - r_valid = false; - return; + const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); + const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); - } break; - } - - } break; - case OP_LESS_EQUAL: { - - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM(<=, BOOL, _bool); - DEFAULT_OP_NUM(<=, INT, _int); - DEFAULT_OP_NUM(<=, REAL, _real); - DEFAULT_OP_STR(<=, STRING, String); - DEFAULT_OP_LOCALMEM(<=, VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_LOCALMEM(<=, VECTOR3, Vector3); - DEFAULT_OP_FAIL(PLANE); - DEFAULT_OP_FAIL(QUAT); - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_LOCALMEM(<=, _RID, RID); - case OBJECT: { - - if (p_b.type == OBJECT) - _RETURN((p_a._get_obj().obj <= p_b._get_obj().obj)); - } break; - DEFAULT_OP_FAIL(DICTIONARY); - DEFAULT_OP_FAIL(ARRAY); - DEFAULT_OP_FAIL(POOL_BYTE_ARRAY); - DEFAULT_OP_FAIL(POOL_INT_ARRAY); - DEFAULT_OP_FAIL(POOL_REAL_ARRAY); - DEFAULT_OP_FAIL(POOL_STRING_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR2_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR3_ARRAY); - DEFAULT_OP_FAIL(POOL_COLOR_ARRAY); - case VARIANT_MAX: { - r_valid = false; - return; + int l = arr_a->size(); + if (arr_b->size() < l) + _RETURN(false); + for (int i = 0; i < l; i++) { + if (!((*arr_a)[i] < (*arr_b)[i])) { + _RETURN(true); + } + } - } break; + _RETURN(false); } - } break; - case OP_GREATER: { + DEFAULT_OP_NUM(math, OP_LESS, INT, <, _int); + DEFAULT_OP_NUM(math, OP_LESS, REAL, <, _real); + DEFAULT_OP_STR(math, OP_LESS, STRING, <, String); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2, <, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS, _RID, <, RID); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_BYTE_ARRAY, uint8_t); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_INT_ARRAY, int); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_REAL_ARRAY, real_t); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR2_ARRAY, Vector3); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_COLOR_ARRAY, Color); + + CASE_TYPE(math, OP_LESS, NIL) + CASE_TYPE(math, OP_LESS, RECT2) + CASE_TYPE(math, OP_LESS, TRANSFORM2D) + CASE_TYPE(math, OP_LESS, PLANE) + CASE_TYPE(math, OP_LESS, QUAT) + CASE_TYPE(math, OP_LESS, RECT3) + CASE_TYPE(math, OP_LESS, BASIS) + CASE_TYPE(math, OP_LESS, TRANSFORM) + CASE_TYPE(math, OP_LESS, COLOR) + CASE_TYPE(math, OP_LESS, NODE_PATH) + CASE_TYPE(math, OP_LESS, DICTIONARY) + _RETURN_FAIL; + } - Variant res; - evaluate(OP_LESS, p_b, p_a, res, r_valid); - if (!r_valid) - return; - _RETURN(res); + SWITCH_OP(math, OP_LESS_EQUAL, p_a.type) { + CASE_TYPE(math, OP_LESS_EQUAL, OBJECT) { + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj <= p_b._get_obj().obj)); + } + + DEFAULT_OP_NUM(math, OP_LESS_EQUAL, INT, <=, _int); + DEFAULT_OP_NUM(math, OP_LESS_EQUAL, REAL, <=, _real); + DEFAULT_OP_STR(math, OP_LESS_EQUAL, STRING, <=, String); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2, <=, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, _RID, <=, RID); + + CASE_TYPE(math, OP_LESS_EQUAL, NIL) + CASE_TYPE(math, OP_LESS_EQUAL, BOOL) + CASE_TYPE(math, OP_LESS_EQUAL, RECT2) + CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM2D) + CASE_TYPE(math, OP_LESS_EQUAL, PLANE) + CASE_TYPE(math, OP_LESS_EQUAL, QUAT) + CASE_TYPE(math, OP_LESS_EQUAL, RECT3) + CASE_TYPE(math, OP_LESS_EQUAL, BASIS) + CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM) + CASE_TYPE(math, OP_LESS_EQUAL, COLOR) + CASE_TYPE(math, OP_LESS_EQUAL, NODE_PATH) + CASE_TYPE(math, OP_LESS_EQUAL, DICTIONARY) + CASE_TYPE(math, OP_LESS_EQUAL, ARRAY) + CASE_TYPE(math, OP_LESS_EQUAL, POOL_BYTE_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_INT_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_REAL_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_COLOR_ARRAY); + _RETURN_FAIL; + } - } break; - case OP_GREATER_EQUAL: { + SWITCH_OP(math, OP_GREATER, p_a.type) { + CASE_TYPE(math, OP_GREATER, BOOL) { + if (p_b.type != BOOL) + _RETURN_FAIL; - Variant res; - evaluate(OP_LESS_EQUAL, p_b, p_a, res, r_valid); - if (!r_valid) - return; - _RETURN(res); - } break; - //mathematic - case OP_ADD: { - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM(+, BOOL, _bool); - DEFAULT_OP_NUM(+, INT, _int); - DEFAULT_OP_NUM(+, REAL, _real); - DEFAULT_OP_STR(+, STRING, String); - DEFAULT_OP_LOCALMEM(+, VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_LOCALMEM(+, VECTOR3, Vector3); - DEFAULT_OP_FAIL(PLANE); - DEFAULT_OP_LOCALMEM(+, QUAT, Quat); - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_FAIL(_RID); - DEFAULT_OP_FAIL(OBJECT); - DEFAULT_OP_FAIL(DICTIONARY); - - case ARRAY: { - if (p_a.type != p_b.type) { - r_valid = false; - return; - } - const Array &array_a = *reinterpret_cast<const Array *>(p_a._data._mem); - const Array &array_b = *reinterpret_cast<const Array *>(p_b._data._mem); - Array sum; - int asize = array_a.size(); - int bsize = array_b.size(); - sum.resize(asize + bsize); - for (int i = 0; i < asize; i++) - sum[i] = array_a[i]; - for (int i = 0; i < bsize; i++) - sum[i + asize] = array_b[i]; - _RETURN(sum); - } - DEFAULT_OP_ARRAY_ADD(POOL_BYTE_ARRAY, uint8_t); - DEFAULT_OP_ARRAY_ADD(POOL_INT_ARRAY, int); - DEFAULT_OP_ARRAY_ADD(POOL_REAL_ARRAY, real_t); - DEFAULT_OP_ARRAY_ADD(POOL_STRING_ARRAY, String); - DEFAULT_OP_ARRAY_ADD(POOL_VECTOR2_ARRAY, Vector2); - DEFAULT_OP_ARRAY_ADD(POOL_VECTOR3_ARRAY, Vector3); - DEFAULT_OP_ARRAY_ADD(POOL_COLOR_ARRAY, Color); - case VARIANT_MAX: { - r_valid = false; - return; + if (p_a._data._bool == p_b._data._bool) + _RETURN(false); - } break; - } - } break; - case OP_SUBSTRACT: { - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM(-, BOOL, _bool); - DEFAULT_OP_NUM(-, INT, _int); - DEFAULT_OP_NUM(-, REAL, _real); - DEFAULT_OP_FAIL(STRING); - DEFAULT_OP_LOCALMEM(-, VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_LOCALMEM(-, VECTOR3, Vector3); - DEFAULT_OP_FAIL(PLANE); - DEFAULT_OP_LOCALMEM(-, QUAT, Quat); - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_FAIL(_RID); - DEFAULT_OP_FAIL(OBJECT); - DEFAULT_OP_FAIL(DICTIONARY); - DEFAULT_OP_FAIL(ARRAY); - DEFAULT_OP_FAIL(POOL_BYTE_ARRAY); - DEFAULT_OP_FAIL(POOL_INT_ARRAY); - DEFAULT_OP_FAIL(POOL_REAL_ARRAY); - DEFAULT_OP_FAIL(POOL_STRING_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR2_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR3_ARRAY); - DEFAULT_OP_FAIL(POOL_COLOR_ARRAY); - case VARIANT_MAX: { - r_valid = false; - return; + if (!p_a._data._bool && p_b._data._bool) + _RETURN(false); - } break; + _RETURN(true); } - } break; - case OP_MULTIPLY: { - switch (p_a.type) { - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM(*, BOOL, _bool); - DEFAULT_OP_NUM_VEC(*, INT, _int); - DEFAULT_OP_NUM_VEC(*, REAL, _real); - DEFAULT_OP_FAIL(STRING); - DEFAULT_OP_LOCALMEM_NUM(*, VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - case TRANSFORM2D: { + CASE_TYPE(math, OP_GREATER, OBJECT) { + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj > p_b._get_obj().obj)); + } - if (p_b.type == TRANSFORM2D) { - _RETURN(*p_a._data._transform2d * *p_b._data._transform2d); - }; - if (p_b.type == VECTOR2) { - _RETURN(p_a._data._transform2d->xform(*(const Vector2 *)p_b._data._mem)); - }; - r_valid = false; - return; - } break; - DEFAULT_OP_LOCALMEM_NUM(*, VECTOR3, Vector3); - DEFAULT_OP_FAIL(PLANE); - case QUAT: { - - switch (p_b.type) { - case VECTOR3: { - - _RETURN(reinterpret_cast<const Quat *>(p_a._data._mem)->xform(*(const Vector3 *)p_b._data._mem)); - } break; - case QUAT: { - - _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * *reinterpret_cast<const Quat *>(p_b._data._mem)); - } break; - case REAL: { - _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * p_b._data._real); - } break; - default: {} - }; - r_valid = false; - return; - } break; - DEFAULT_OP_FAIL(RECT3); - case BASIS: { + CASE_TYPE(math, OP_GREATER, ARRAY) { + if (p_b.type != ARRAY) + _RETURN_FAIL; - switch (p_b.type) { - case VECTOR3: { + const Array *arr_a = reinterpret_cast<const Array *>(p_a._data._mem); + const Array *arr_b = reinterpret_cast<const Array *>(p_b._data._mem); - _RETURN(p_a._data._basis->xform(*(const Vector3 *)p_b._data._mem)); - }; - case BASIS: { + int l = arr_a->size(); + if (arr_b->size() > l) + _RETURN(false); + for (int i = 0; i < l; i++) { + if (((*arr_a)[i] < (*arr_b)[i])) { + _RETURN(false); + } + } - _RETURN(*p_a._data._basis * *p_b._data._basis); - }; - default: {} - }; - r_valid = false; - return; - } break; - case TRANSFORM: { + _RETURN(true); + } + + DEFAULT_OP_NUM(math, OP_GREATER, INT, >, _int); + DEFAULT_OP_NUM(math, OP_GREATER, REAL, >, _real); + DEFAULT_OP_STR_REV(math, OP_GREATER, STRING, <, String); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2, <, Vector2); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, _RID, <, RID); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_BYTE_ARRAY, uint8_t); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_INT_ARRAY, int); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_REAL_ARRAY, real_t); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR2_ARRAY, Vector3); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_COLOR_ARRAY, Color); + + CASE_TYPE(math, OP_GREATER, NIL) + CASE_TYPE(math, OP_GREATER, RECT2) + CASE_TYPE(math, OP_GREATER, TRANSFORM2D) + CASE_TYPE(math, OP_GREATER, PLANE) + CASE_TYPE(math, OP_GREATER, QUAT) + CASE_TYPE(math, OP_GREATER, RECT3) + CASE_TYPE(math, OP_GREATER, BASIS) + CASE_TYPE(math, OP_GREATER, TRANSFORM) + CASE_TYPE(math, OP_GREATER, COLOR) + CASE_TYPE(math, OP_GREATER, NODE_PATH) + CASE_TYPE(math, OP_GREATER, DICTIONARY) + _RETURN_FAIL; + } - switch (p_b.type) { - case VECTOR3: { + SWITCH_OP(math, OP_GREATER_EQUAL, p_a.type) { + CASE_TYPE(math, OP_GREATER_EQUAL, OBJECT) { + if (p_b.type != OBJECT) + _RETURN_FAIL; + _RETURN((p_a._get_obj().obj >= p_b._get_obj().obj)); + } + + DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, INT, >=, _int); + DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, REAL, >=, _real); + DEFAULT_OP_STR_REV(math, OP_GREATER_EQUAL, STRING, <=, String); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2, <=, Vector2); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, _RID, <=, RID); + + CASE_TYPE(math, OP_GREATER_EQUAL, NIL) + CASE_TYPE(math, OP_GREATER_EQUAL, BOOL) + CASE_TYPE(math, OP_GREATER_EQUAL, RECT2) + CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM2D) + CASE_TYPE(math, OP_GREATER_EQUAL, PLANE) + CASE_TYPE(math, OP_GREATER_EQUAL, QUAT) + CASE_TYPE(math, OP_GREATER_EQUAL, RECT3) + CASE_TYPE(math, OP_GREATER_EQUAL, BASIS) + CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM) + CASE_TYPE(math, OP_GREATER_EQUAL, COLOR) + CASE_TYPE(math, OP_GREATER_EQUAL, NODE_PATH) + CASE_TYPE(math, OP_GREATER_EQUAL, DICTIONARY) + CASE_TYPE(math, OP_GREATER_EQUAL, ARRAY) + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_BYTE_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_INT_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_REAL_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_COLOR_ARRAY); + _RETURN_FAIL; + } - _RETURN(p_a._data._transform->xform(*(const Vector3 *)p_b._data._mem)); - }; - case TRANSFORM: { + SWITCH_OP(math, OP_ADD, p_a.type) { + CASE_TYPE(math, OP_ADD, ARRAY) { + if (p_a.type != p_b.type) + _RETURN_FAIL; + + const Array &array_a = *reinterpret_cast<const Array *>(p_a._data._mem); + const Array &array_b = *reinterpret_cast<const Array *>(p_b._data._mem); + Array sum; + int asize = array_a.size(); + int bsize = array_b.size(); + sum.resize(asize + bsize); + for (int i = 0; i < asize; i++) + sum[i] = array_a[i]; + for (int i = 0; i < bsize; i++) + sum[i + asize] = array_b[i]; + _RETURN(sum); + } + + DEFAULT_OP_NUM(math, OP_ADD, INT, +, _int); + DEFAULT_OP_NUM(math, OP_ADD, REAL, +, _real); + DEFAULT_OP_STR(math, OP_ADD, STRING, +, String); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2, +, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3, +, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_ADD, QUAT, +, Quat); + DEFAULT_OP_LOCALMEM(math, OP_ADD, COLOR, +, Color); + + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_BYTE_ARRAY, uint8_t); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_INT_ARRAY, int); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_REAL_ARRAY, real_t); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_COLOR_ARRAY, Color); + + CASE_TYPE(math, OP_ADD, NIL) + CASE_TYPE(math, OP_ADD, BOOL) + CASE_TYPE(math, OP_ADD, RECT2) + CASE_TYPE(math, OP_ADD, TRANSFORM2D) + CASE_TYPE(math, OP_ADD, PLANE) + CASE_TYPE(math, OP_ADD, RECT3) + CASE_TYPE(math, OP_ADD, BASIS) + CASE_TYPE(math, OP_ADD, TRANSFORM) + CASE_TYPE(math, OP_ADD, NODE_PATH) + CASE_TYPE(math, OP_ADD, _RID) + CASE_TYPE(math, OP_ADD, OBJECT) + CASE_TYPE(math, OP_ADD, DICTIONARY) + _RETURN_FAIL; + } - _RETURN(*p_a._data._transform * *p_b._data._transform); - }; - default: {} - }; - r_valid = false; - return; - } break; - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_FAIL(_RID); - DEFAULT_OP_FAIL(OBJECT); - DEFAULT_OP_FAIL(DICTIONARY); - DEFAULT_OP_FAIL(ARRAY); - DEFAULT_OP_FAIL(POOL_BYTE_ARRAY); - DEFAULT_OP_FAIL(POOL_INT_ARRAY); - DEFAULT_OP_FAIL(POOL_REAL_ARRAY); - DEFAULT_OP_FAIL(POOL_STRING_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR2_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR3_ARRAY); - DEFAULT_OP_FAIL(POOL_COLOR_ARRAY); - case VARIANT_MAX: { - r_valid = false; - return; + SWITCH_OP(math, OP_SUBTRACT, p_a.type) { + DEFAULT_OP_NUM(math, OP_SUBTRACT, INT, -, _int); + DEFAULT_OP_NUM(math, OP_SUBTRACT, REAL, -, _real); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2, -, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3, -, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, QUAT, -, Quat); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, COLOR, -, Color); + + CASE_TYPE(math, OP_SUBTRACT, NIL) + CASE_TYPE(math, OP_SUBTRACT, BOOL) + CASE_TYPE(math, OP_SUBTRACT, STRING) + CASE_TYPE(math, OP_SUBTRACT, RECT2) + CASE_TYPE(math, OP_SUBTRACT, TRANSFORM2D) + CASE_TYPE(math, OP_SUBTRACT, PLANE) + CASE_TYPE(math, OP_SUBTRACT, RECT3) + CASE_TYPE(math, OP_SUBTRACT, BASIS) + CASE_TYPE(math, OP_SUBTRACT, TRANSFORM) + CASE_TYPE(math, OP_SUBTRACT, NODE_PATH) + CASE_TYPE(math, OP_SUBTRACT, _RID) + CASE_TYPE(math, OP_SUBTRACT, OBJECT) + CASE_TYPE(math, OP_SUBTRACT, DICTIONARY) + CASE_TYPE(math, OP_SUBTRACT, ARRAY) + CASE_TYPE(math, OP_SUBTRACT, POOL_BYTE_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_INT_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_REAL_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_COLOR_ARRAY); + _RETURN_FAIL; + } - } break; + SWITCH_OP(math, OP_MULTIPLY, p_a.type) { + CASE_TYPE(math, OP_MULTIPLY, TRANSFORM2D) { + switch (p_b.type) { + case TRANSFORM2D: { + _RETURN(*p_a._data._transform2d * *p_b._data._transform2d); + } + case VECTOR2: { + _RETURN(p_a._data._transform2d->xform(*(const Vector2 *)p_b._data._mem)); + } + default: _RETURN_FAIL; + } } - } break; - case OP_DIVIDE: { - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM(/, BOOL, _bool); - case INT: { - switch (p_b.type) { - case BOOL: { - int64_t b = p_b._data._bool; - if (b == 0) { - r_valid = false; - _RETURN("Division By False"); - } - _RETURN(p_a._data._int / b); - - } break; - case INT: { - int64_t b = p_b._data._int; - if (b == 0) { + CASE_TYPE(math, OP_MULTIPLY, QUAT) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(reinterpret_cast<const Quat *>(p_a._data._mem)->xform(*(const Vector3 *)p_b._data._mem)); + } + case QUAT: { + _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * *reinterpret_cast<const Quat *>(p_b._data._mem)); + } + case REAL: { + _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) * p_b._data._real); + } + default: _RETURN_FAIL; + } + } - r_valid = false; - _RETURN("Division By Zero"); - } - _RETURN(p_a._data._int / b); + CASE_TYPE(math, OP_MULTIPLY, BASIS) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(p_a._data._basis->xform(*(const Vector3 *)p_b._data._mem)); + } + case BASIS: { + _RETURN(*p_a._data._basis * *p_b._data._basis); + } + default: _RETURN_FAIL; + } + } - } break; - case REAL: _RETURN(p_a._data._int / p_b._data._real); - default: {} + CASE_TYPE(math, OP_MULTIPLY, TRANSFORM) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(p_a._data._transform->xform(*(const Vector3 *)p_b._data._mem)); } - r_valid = false; - return; - }; - DEFAULT_OP_NUM(/, REAL, _real); - DEFAULT_OP_FAIL(STRING); - DEFAULT_OP_LOCALMEM_NUM(/, VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_LOCALMEM_NUM(/, VECTOR3, Vector3); - DEFAULT_OP_FAIL(PLANE); - case QUAT: { - if (p_b.type != REAL) { - r_valid = false; - return; + case TRANSFORM: { + _RETURN(*p_a._data._transform * *p_b._data._transform); } - _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) / p_b._data._real); - } break; - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_FAIL(_RID); - DEFAULT_OP_FAIL(OBJECT); - DEFAULT_OP_FAIL(DICTIONARY); - DEFAULT_OP_FAIL(ARRAY); - DEFAULT_OP_FAIL(POOL_BYTE_ARRAY); - DEFAULT_OP_FAIL(POOL_INT_ARRAY); - DEFAULT_OP_FAIL(POOL_REAL_ARRAY); - DEFAULT_OP_FAIL(POOL_STRING_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR2_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR3_ARRAY); - DEFAULT_OP_FAIL(POOL_COLOR_ARRAY); - case VARIANT_MAX: { - r_valid = false; - return; + default: _RETURN_FAIL; + } + } - } break; - } - - } break; - case OP_POSITIVE: { - // Simple case when user defines variable as +value. - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_FAIL(STRING); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - DEFAULT_OP_NUM_POS(BOOL, _bool); - DEFAULT_OP_NUM_POS(INT, _int); - DEFAULT_OP_NUM_POS(REAL, _real); - DEFAULT_OP_LOCALMEM_POS(VECTOR3, Vector3); - DEFAULT_OP_LOCALMEM_POS(PLANE, Plane); - DEFAULT_OP_LOCALMEM_POS(QUAT, Quat); - DEFAULT_OP_LOCALMEM_POS(VECTOR2, Vector2); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_FAIL(_RID); - DEFAULT_OP_FAIL(OBJECT); - DEFAULT_OP_FAIL(DICTIONARY); - DEFAULT_OP_FAIL(ARRAY); - DEFAULT_OP_FAIL(POOL_BYTE_ARRAY); - DEFAULT_OP_FAIL(POOL_INT_ARRAY); - DEFAULT_OP_FAIL(POOL_REAL_ARRAY); - DEFAULT_OP_FAIL(POOL_STRING_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR2_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR3_ARRAY); - DEFAULT_OP_FAIL(POOL_COLOR_ARRAY); - case VARIANT_MAX: { - r_valid = false; - return; + DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, INT, *, _int); + DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, REAL, *, _real); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2, *, Vector2); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3, *, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, COLOR, *, Color); + + CASE_TYPE(math, OP_MULTIPLY, NIL) + CASE_TYPE(math, OP_MULTIPLY, BOOL) + CASE_TYPE(math, OP_MULTIPLY, STRING) + CASE_TYPE(math, OP_MULTIPLY, RECT2) + CASE_TYPE(math, OP_MULTIPLY, PLANE) + CASE_TYPE(math, OP_MULTIPLY, RECT3) + CASE_TYPE(math, OP_MULTIPLY, NODE_PATH) + CASE_TYPE(math, OP_MULTIPLY, _RID) + CASE_TYPE(math, OP_MULTIPLY, OBJECT) + CASE_TYPE(math, OP_MULTIPLY, DICTIONARY) + CASE_TYPE(math, OP_MULTIPLY, ARRAY) + CASE_TYPE(math, OP_MULTIPLY, POOL_BYTE_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_INT_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_REAL_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_COLOR_ARRAY); + _RETURN_FAIL; + } - } break; - } - } break; - case OP_NEGATE: { - switch (p_a.type) { - - DEFAULT_OP_FAIL(NIL); - DEFAULT_OP_NUM_NEG(BOOL, _bool); - DEFAULT_OP_NUM_NEG(INT, _int); - DEFAULT_OP_NUM_NEG(REAL, _real); - DEFAULT_OP_FAIL(STRING); - DEFAULT_OP_LOCALMEM_NEG(VECTOR2, Vector2); - DEFAULT_OP_FAIL(RECT2); - DEFAULT_OP_FAIL(TRANSFORM2D); - DEFAULT_OP_LOCALMEM_NEG(VECTOR3, Vector3); - DEFAULT_OP_LOCALMEM_NEG(PLANE, Plane); - DEFAULT_OP_LOCALMEM_NEG(QUAT, Quat); - DEFAULT_OP_FAIL(RECT3); - DEFAULT_OP_FAIL(BASIS); - DEFAULT_OP_FAIL(TRANSFORM); - - DEFAULT_OP_FAIL(COLOR); - - DEFAULT_OP_FAIL(NODE_PATH); - DEFAULT_OP_FAIL(_RID); - DEFAULT_OP_FAIL(OBJECT); - DEFAULT_OP_FAIL(DICTIONARY); - DEFAULT_OP_FAIL(ARRAY); - DEFAULT_OP_FAIL(POOL_BYTE_ARRAY); - DEFAULT_OP_FAIL(POOL_INT_ARRAY); - DEFAULT_OP_FAIL(POOL_REAL_ARRAY); - DEFAULT_OP_FAIL(POOL_STRING_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR2_ARRAY); - DEFAULT_OP_FAIL(POOL_VECTOR3_ARRAY); - DEFAULT_OP_FAIL(POOL_COLOR_ARRAY); - case VARIANT_MAX: { + SWITCH_OP(math, OP_DIVIDE, p_a.type) { + CASE_TYPE(math, OP_DIVIDE, QUAT) { + if (p_b.type != REAL) + _RETURN_FAIL; +#ifdef DEBUG_ENABLED + if (p_b._data._real == 0) { r_valid = false; - return; + _RETURN("Division By Zero"); + } +#endif + _RETURN(*reinterpret_cast<const Quat *>(p_a._data._mem) / p_b._data._real); + } + + DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, INT, _int); + DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, REAL, _real); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2, /, Vector2); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3, /, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, COLOR, /, Color); + + CASE_TYPE(math, OP_DIVIDE, NIL) + CASE_TYPE(math, OP_DIVIDE, BOOL) + CASE_TYPE(math, OP_DIVIDE, STRING) + CASE_TYPE(math, OP_DIVIDE, RECT2) + CASE_TYPE(math, OP_DIVIDE, TRANSFORM2D) + CASE_TYPE(math, OP_DIVIDE, PLANE) + CASE_TYPE(math, OP_DIVIDE, RECT3) + CASE_TYPE(math, OP_DIVIDE, BASIS) + CASE_TYPE(math, OP_DIVIDE, TRANSFORM) + CASE_TYPE(math, OP_DIVIDE, NODE_PATH) + CASE_TYPE(math, OP_DIVIDE, _RID) + CASE_TYPE(math, OP_DIVIDE, OBJECT) + CASE_TYPE(math, OP_DIVIDE, DICTIONARY) + CASE_TYPE(math, OP_DIVIDE, ARRAY) + CASE_TYPE(math, OP_DIVIDE, POOL_BYTE_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_INT_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_REAL_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_COLOR_ARRAY); + _RETURN_FAIL; + } - } break; - } - } break; - case OP_MODULE: { - if (p_a.type == INT && p_b.type == INT) { + SWITCH_OP(math, OP_POSITIVE, p_a.type) { + DEFAULT_OP_NUM_POS(math, OP_POSITIVE, INT, _int); + DEFAULT_OP_NUM_POS(math, OP_POSITIVE, REAL, _real); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, PLANE, Plane); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, QUAT, Quat); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2, Vector2); + + CASE_TYPE(math, OP_POSITIVE, NIL) + CASE_TYPE(math, OP_POSITIVE, BOOL) + CASE_TYPE(math, OP_POSITIVE, STRING) + CASE_TYPE(math, OP_POSITIVE, RECT2) + CASE_TYPE(math, OP_POSITIVE, TRANSFORM2D) + CASE_TYPE(math, OP_POSITIVE, RECT3) + CASE_TYPE(math, OP_POSITIVE, BASIS) + CASE_TYPE(math, OP_POSITIVE, TRANSFORM) + CASE_TYPE(math, OP_POSITIVE, COLOR) + CASE_TYPE(math, OP_POSITIVE, NODE_PATH) + CASE_TYPE(math, OP_POSITIVE, _RID) + CASE_TYPE(math, OP_POSITIVE, OBJECT) + CASE_TYPE(math, OP_POSITIVE, DICTIONARY) + CASE_TYPE(math, OP_POSITIVE, ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_BYTE_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_INT_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_REAL_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_STRING_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR2_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_COLOR_ARRAY) + _RETURN_FAIL; + } + + SWITCH_OP(math, OP_NEGATE, p_a.type) { + DEFAULT_OP_NUM_NEG(math, OP_NEGATE, INT, _int); + DEFAULT_OP_NUM_NEG(math, OP_NEGATE, REAL, _real); + + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2, Vector2); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, PLANE, Plane); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, QUAT, Quat); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, COLOR, Color); + + CASE_TYPE(math, OP_NEGATE, NIL) + CASE_TYPE(math, OP_NEGATE, BOOL) + CASE_TYPE(math, OP_NEGATE, STRING) + CASE_TYPE(math, OP_NEGATE, RECT2) + CASE_TYPE(math, OP_NEGATE, TRANSFORM2D) + CASE_TYPE(math, OP_NEGATE, RECT3) + CASE_TYPE(math, OP_NEGATE, BASIS) + CASE_TYPE(math, OP_NEGATE, TRANSFORM) + CASE_TYPE(math, OP_NEGATE, NODE_PATH) + CASE_TYPE(math, OP_NEGATE, _RID) + CASE_TYPE(math, OP_NEGATE, OBJECT) + CASE_TYPE(math, OP_NEGATE, DICTIONARY) + CASE_TYPE(math, OP_NEGATE, ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_BYTE_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_INT_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_REAL_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_STRING_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR2_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_COLOR_ARRAY) + _RETURN_FAIL; + } + + SWITCH_OP(math, OP_MODULE, p_a.type) { + CASE_TYPE(math, OP_MODULE, INT) { + if (p_b.type != INT) + _RETURN_FAIL; #ifdef DEBUG_ENABLED if (p_b._data._int == 0) { r_valid = false; @@ -827,8 +1007,9 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, const Variant & } #endif _RETURN(p_a._data._int % p_b._data._int); + } - } else if (p_a.type == STRING) { + CASE_TYPE(math, OP_MODULE, STRING) { const String *format = reinterpret_cast<const String *>(p_a._data._mem); String result; @@ -847,119 +1028,143 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, const Variant & _RETURN(result); } - r_valid = false; - return; + CASE_TYPE(math, OP_MODULE, NIL) + CASE_TYPE(math, OP_MODULE, BOOL) + CASE_TYPE(math, OP_MODULE, REAL) + CASE_TYPE(math, OP_MODULE, VECTOR2) + CASE_TYPE(math, OP_MODULE, RECT2) + CASE_TYPE(math, OP_MODULE, VECTOR3) + CASE_TYPE(math, OP_MODULE, TRANSFORM2D) + CASE_TYPE(math, OP_MODULE, PLANE) + CASE_TYPE(math, OP_MODULE, QUAT) + CASE_TYPE(math, OP_MODULE, RECT3) + CASE_TYPE(math, OP_MODULE, BASIS) + CASE_TYPE(math, OP_MODULE, TRANSFORM) + CASE_TYPE(math, OP_MODULE, COLOR) + CASE_TYPE(math, OP_MODULE, NODE_PATH) + CASE_TYPE(math, OP_MODULE, _RID) + CASE_TYPE(math, OP_MODULE, OBJECT) + CASE_TYPE(math, OP_MODULE, DICTIONARY) + CASE_TYPE(math, OP_MODULE, ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_BYTE_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_INT_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_REAL_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_STRING_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR2_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_COLOR_ARRAY) + _RETURN_FAIL; + } - } break; - case OP_STRING_CONCAT: { + SWITCH_OP(math, OP_STRING_CONCAT, p_a.type) { + CASE_TYPE_ALL(math, OP_STRING_CONCAT) _RETURN(p_a.operator String() + p_b.operator String()); - } break; - //bitwise - case OP_SHIFT_LEFT: { - if (p_a.type == INT && p_b.type == INT) + } + + SWITCH_OP(math, OP_SHIFT_LEFT, p_a.type) { + CASE_TYPE(math, OP_SHIFT_LEFT, INT) { + if (p_b.type != INT) + _RETURN_FAIL; _RETURN(p_a._data._int << p_b._data._int); + } - r_valid = false; - return; + CASE_TYPE_ALL_BUT_INT(math, OP_SHIFT_LEFT) + _RETURN_FAIL; + } - } break; - case OP_SHIFT_RIGHT: { - if (p_a.type == INT && p_b.type == INT) + SWITCH_OP(math, OP_SHIFT_RIGHT, p_a.type) { + CASE_TYPE(math, OP_SHIFT_RIGHT, INT) { + if (p_b.type != INT) + _RETURN_FAIL; _RETURN(p_a._data._int >> p_b._data._int); + } - r_valid = false; - return; + CASE_TYPE_ALL_BUT_INT(math, OP_SHIFT_RIGHT) + _RETURN_FAIL; + } - } break; - case OP_BIT_AND: { - if (p_a.type == INT && p_b.type == INT) + SWITCH_OP(math, OP_BIT_AND, p_a.type) { + CASE_TYPE(math, OP_BIT_AND, INT) { + if (p_b.type != INT) + _RETURN_FAIL; _RETURN(p_a._data._int & p_b._data._int); + } - r_valid = false; - return; - - } break; - case OP_BIT_OR: { + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_AND) + _RETURN_FAIL; + } - if (p_a.type == INT && p_b.type == INT) + SWITCH_OP(math, OP_BIT_OR, p_a.type) { + CASE_TYPE(math, OP_BIT_OR, INT) { + if (p_b.type != INT) + _RETURN_FAIL; _RETURN(p_a._data._int | p_b._data._int); + } - r_valid = false; - return; - - } break; - case OP_BIT_XOR: { + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_OR) + _RETURN_FAIL; + } - if (p_a.type == INT && p_b.type == INT) + SWITCH_OP(math, OP_BIT_XOR, p_a.type) { + CASE_TYPE(math, OP_BIT_XOR, INT) { + if (p_b.type != INT) + _RETURN_FAIL; _RETURN(p_a._data._int ^ p_b._data._int); + } - r_valid = false; - return; - - } break; - case OP_BIT_NEGATE: { + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_XOR) + _RETURN_FAIL; + } - if (p_a.type == INT) + SWITCH_OP(math, OP_BIT_NEGATE, p_a.type) { + CASE_TYPE(math, OP_BIT_NEGATE, INT) { _RETURN(~p_a._data._int); + } - r_valid = false; - return; + CASE_TYPE_ALL_BUT_INT(math, OP_BIT_NEGATE) + _RETURN_FAIL; + } - } break; - //logic - case OP_AND: { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - bool r = p_b.booleanize(r_valid); - if (!r_valid) - return; + SWITCH_OP(math, OP_AND, p_a.type) { + CASE_TYPE_ALL(math, OP_AND) { + bool l = p_a.booleanize(); + bool r = p_b.booleanize(); - _RETURN(l && r); - } break; - case OP_OR: { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - bool r = p_b.booleanize(r_valid); - if (!r_valid) - return; + _RETURN(l && r); + } + } - _RETURN(l || r); + SWITCH_OP(math, OP_OR, p_a.type) { + CASE_TYPE_ALL(math, OP_OR) { + bool l = p_a.booleanize(); + bool r = p_b.booleanize(); - } break; - case OP_XOR: { - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - bool r = p_b.booleanize(r_valid); - if (!r_valid) - return; + _RETURN(l || r); + } + } - _RETURN((l || r) && !(l && r)); - } break; - case OP_NOT: { + SWITCH_OP(math, OP_XOR, p_a.type) { + CASE_TYPE_ALL(math, OP_XOR) { + bool l = p_a.booleanize(); + bool r = p_b.booleanize(); - bool l = p_a.booleanize(r_valid); - if (!r_valid) - return; - _RETURN(!l); + _RETURN((l || r) && !(l && r)); + } + } - } break; - case OP_IN: { + SWITCH_OP(math, OP_NOT, p_a.type) { + CASE_TYPE_ALL(math, OP_NOT) { + bool l = p_a.booleanize(); + _RETURN(!l); + } + } + SWITCH_OP(math, OP_IN, p_a.type) { + CASE_TYPE_ALL(math, OP_IN) _RETURN(p_b.in(p_a, &r_valid)); - - } break; - case OP_MAX: { - - r_valid = false; - ERR_FAIL(); } } - - r_valid = false; } void Variant::set_named(const StringName &p_index, const Variant &p_value, bool *r_valid) { @@ -1512,7 +1717,8 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) DEFAULT_OP_DVECTOR_SET(POOL_VECTOR2_ARRAY, Vector2, p_value.type != Variant::VECTOR2) // 25 DEFAULT_OP_DVECTOR_SET(POOL_VECTOR3_ARRAY, Vector3, p_value.type != Variant::VECTOR3) DEFAULT_OP_DVECTOR_SET(POOL_COLOR_ARRAY, Color, p_value.type != Variant::COLOR) - default: return; + default: + return; } } @@ -1885,7 +2091,8 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { DEFAULT_OP_DVECTOR_GET(POOL_VECTOR2_ARRAY, Vector2) // 25 DEFAULT_OP_DVECTOR_GET(POOL_VECTOR3_ARRAY, Vector3) DEFAULT_OP_DVECTOR_GET(POOL_COLOR_ARRAY, Color) - default: return Variant(); + default: + return Variant(); } return Variant(); @@ -2374,7 +2581,8 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { return true; } break; - default: {} + default: { + } } valid = false; @@ -2401,7 +2609,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { return true; } break; case VECTOR2: { - int64_t to = reinterpret_cast<const Vector3 *>(_data._mem)->y; + int64_t to = reinterpret_cast<const Vector2 *>(_data._mem)->y; int64_t idx = r_iter; idx++; @@ -2793,7 +3001,9 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = Color(r, g, b, a); } return; - default: { r_dst = c < 0.5 ? a : b; } + default: { + r_dst = c < 0.5 ? a : b; + } return; } } |