diff --git a/platform/sfwl.cpp b/platform/sfw.cpp similarity index 63% rename from platform/sfwl.cpp rename to platform/sfw.cpp index 0ac921f..aadae81 100644 --- a/platform/sfwl.cpp +++ b/platform/sfw.cpp @@ -165,13 +165,13 @@ Any contribution to this repository is implicitly subjected to the same release #include #endif -#ifndef SFWL_H -#include "sfwl.h" +#ifndef SFW_H +#include "sfw.h" #endif //=================== CORE SECTION =================== -#line 1 "sfwl/core/ucaps.h" +#line 1 "sfw/core/ucaps.h" /*************************************************************************/ /* ucaps.h */ @@ -1561,7 +1561,7 @@ static int _find_lower(int ch) { #line 0 -#line 1 "sfwl/core/mutex.cpp" +#line 1 "sfw/core/mutex.cpp" /*************************************************************************/ /* mutex.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -1585,7 +1585,7 @@ template class MutexImpl; #endif #line 0 -#line 1 "sfwl/core/safe_refcount.cpp" +#line 1 "sfw/core/safe_refcount.cpp" /*************************************************************************/ /* safe_refcount.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -1597,14 +1597,126 @@ template class MutexImpl; void check_lockless_atomics() { // Doing the check for the types we actually care about if (!std::atomic{}.is_lock_free() || !std::atomic{}.is_lock_free() || !std::atomic_bool{}.is_lock_free()) { - LOG_WARN("Your compiler doesn't seem to support lockless atomics. Performance will be degraded. Please consider upgrading to a different or newer compiler."); + WARN_PRINT("Your compiler doesn't seem to support lockless atomics. Performance will be degraded. Please consider upgrading to a different or newer compiler."); } } #endif #line 0 -#line 1 "sfwl/core/sfw_time.cpp" +//#include "thread.h" +//#include "core/error_macros.h" +//#include "core/safe_refcount.h" + +#line 1 "sfw/core/thread.cpp" +/*************************************************************************/ +/* thread.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +#if !defined(NO_THREADS) + +Error (*Thread::set_name_func)(const String &) = nullptr; +void (*Thread::set_priority_func)(Thread::Priority) = nullptr; +void (*Thread::init_func)() = nullptr; +void (*Thread::term_func)() = nullptr; + +uint64_t Thread::_thread_id_hash(const std::thread::id &p_t) { + static std::hash hasher; + return hasher(p_t); +} + +Thread::ID Thread::main_thread_id = _thread_id_hash(std::this_thread::get_id()); +static thread_local Thread::ID caller_id = 0; +static thread_local bool caller_id_cached = false; + +void Thread::_set_platform_funcs( + Error (*p_set_name_func)(const String &), + void (*p_set_priority_func)(Thread::Priority), + void (*p_init_func)(), + void (*p_term_func)()) { + Thread::set_name_func = p_set_name_func; + Thread::set_priority_func = p_set_priority_func; + Thread::init_func = p_init_func; + Thread::term_func = p_term_func; +} + +void Thread::callback(Thread *p_self, const Settings &p_settings, Callback p_callback, void *p_userdata) { + caller_id = _thread_id_hash(p_self->thread.get_id()); + caller_id_cached = true; + + if (set_priority_func) { + set_priority_func(p_settings.priority); + } + if (init_func) { + init_func(); + } + + p_callback(p_userdata); + + if (term_func) { + term_func(); + } +} + +void Thread::start(Thread::Callback p_callback, void *p_user, const Settings &p_settings) { + if (id != _thread_id_hash(std::thread::id())) { +#ifdef DEBUG_ENABLED + WARN_PRINT("A Thread object has been re-started without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread."); +#endif + thread.detach(); + std::thread empty_thread; + thread.swap(empty_thread); + } + std::thread new_thread(&Thread::callback, this, p_settings, p_callback, p_user); + thread.swap(new_thread); + id = _thread_id_hash(thread.get_id()); +} + +bool Thread::is_started() const { + return id != _thread_id_hash(std::thread::id()); +} + +void Thread::wait_to_finish() { + if (id != _thread_id_hash(std::thread::id())) { + ERR_FAIL_COND_MSG(id == get_caller_id(), "A Thread can't wait for itself to finish."); + thread.join(); + std::thread empty_thread; + thread.swap(empty_thread); + id = _thread_id_hash(std::thread::id()); + } +} + +Error Thread::set_name(const String &p_name) { + if (set_name_func) { + return set_name_func(p_name); + } + + return ERR_UNAVAILABLE; +} + +Thread::~Thread() { + if (id != _thread_id_hash(std::thread::id())) { +#ifdef DEBUG_ENABLED + LOG_WARN("A Thread object has been destroyed without wait_to_finish() having been called on it. Please do so to ensure correct cleanup of the thread."); +#endif + thread.detach(); + } +} + +Thread::ID Thread::get_caller_id() { + if (likely(caller_id_cached)) { + return caller_id; + } else { + caller_id = _thread_id_hash(std::this_thread::get_id()); + caller_id_cached = true; + return caller_id; + } +} +#endif +#line 0 + +#line 1 "sfw/core/sfw_time.cpp" // ---------------------------------------------------------------------------- // time @@ -1788,7 +1900,7 @@ void SFWTime::sleep_ss(double ss) { } #line 0 -#line 1 "sfwl/core/memory.cpp" +#line 1 "sfw/core/memory.cpp" /*************************************************************************/ /* memory.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -1959,7 +2071,7 @@ _GlobalNil::_GlobalNil() { _GlobalNil _GlobalNilClass::_nil; #line 0 -#line 1 "sfwl/core/pool_vector.cpp" +#line 1 "sfw/core/pool_vector.cpp" /*************************************************************************/ /* pool_vector.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -1999,7 +2111,7 @@ void MemoryPool::cleanup() { } #line 0 -#line 1 "sfwl/core/pool_allocator.cpp" +#line 1 "sfw/core/pool_allocator.cpp" /*************************************************************************/ /* pool_allocator.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -2558,7 +2670,7 @@ PoolAllocator::~PoolAllocator() { #undef COMPACT_CHUNK #line 0 -#line 1 "sfwl/core/random_pcg.cpp" +#line 1 "sfw/core/random_pcg.cpp" /*************************************************************************/ /* random_pcg.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -2590,7 +2702,7 @@ int RandomPCG::random(int p_from, int p_to) { } #line 0 -#line 1 "sfwl/core/math_funcs.cpp" +#line 1 "sfw/core/math_funcs.cpp" /*************************************************************************/ /* math_funcs.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -2761,7 +2873,7 @@ int Math::random(int from, int to) { } #line 0 -#line 1 "sfwl/core/ustring.cpp" +#line 1 "sfw/core/ustring.cpp" /*************************************************************************/ /* ustring.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -7773,7 +7885,7 @@ static double built_in_strtod( if (exp > maxExponent) { exp = maxExponent; - //LOG_WARN("Exponent too high"); + //WARN_PRINT("Exponent too high"); } dblExp = 1.0; for (d = powersOf10; exp != 0; exp >>= 1, ++d) { @@ -8173,7 +8285,7 @@ String RTR(const String &p_text) { } #line 0 -#line 1 "sfwl/core/logger.cpp" +#line 1 "sfw/core/logger.cpp" void RLogger::print_trace(const String &str) { print_trace(str.utf8().get_data()); @@ -8374,7 +8486,7 @@ void RLogger::log_ret_ptr(String *str) { } #line 0 -#line 1 "sfwl/core/string_name.cpp" +#line 1 "sfw/core/string_name.cpp" /*************************************************************************/ /* string_name.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -8421,13 +8533,13 @@ void StringName::cleanup() { } } - LOG_MSG("\nStringName reference ranking (from most to least referenced):\n"); + print_line("\nStringName reference ranking (from most to least referenced):\n"); data.sort_custom(); int unreferenced_stringnames = 0; int rarely_referenced_stringnames = 0; for (int i = 0; i < data.size(); i++) { - LOG_MSG(itos(i + 1) + ": " + data[i]->get_name() + " - " + itos(data[i]->debug_references)); + print_line(itos(i + 1) + ": " + data[i]->get_name() + " - " + itos(data[i]->debug_references)); if (data[i]->debug_references == 0) { unreferenced_stringnames += 1; } else if (data[i]->debug_references < 5) { @@ -8435,8 +8547,8 @@ void StringName::cleanup() { } } - LOG_MSG(vformat("\nOut of %d StringNames, %d StringNames were never referenced during this run (0 times) (%.2f%%).", data.size(), unreferenced_stringnames, unreferenced_stringnames / float(data.size()) * 100)); - LOG_MSG(vformat("Out of %d StringNames, %d StringNames were rarely referenced during this run (1-4 times) (%.2f%%).", data.size(), rarely_referenced_stringnames, rarely_referenced_stringnames / float(data.size()) * 100)); + print_line(vformat("\nOut of %d StringNames, %d StringNames were never referenced during this run (0 times) (%.2f%%).", data.size(), unreferenced_stringnames, unreferenced_stringnames / float(data.size()) * 100)); + print_line(vformat("Out of %d StringNames, %d StringNames were rarely referenced during this run (1-4 times) (%.2f%%).", data.size(), rarely_referenced_stringnames, rarely_referenced_stringnames / float(data.size()) * 100)); } #endif @@ -8450,9 +8562,9 @@ void StringName::cleanup() { lost_strings++; if (OS::get_singleton()->is_stdout_verbose()) { if (d->cname) { - LOG_MSG("Orphan StringName: " + String(d->cname)); + print_line("Orphan StringName: " + String(d->cname)); } else { - LOG_MSG("Orphan StringName: " + String(d->name)); + print_line("Orphan StringName: " + String(d->name)); } } } @@ -8893,7 +9005,3839 @@ bool operator!=(const char *p_name, const StringName &p_string_name) { */ #line 0 -#line 1 "sfwl/core/color.cpp" +#line 1 "sfw/core/aabb.cpp" +/*************************************************************************/ +/* aabb.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +real_t AABB::get_volume() const { + return size.x * size.y * size.z; +} + +bool AABB::operator==(const AABB &p_rval) const { + return ((position == p_rval.position) && (size == p_rval.size)); +} +bool AABB::operator!=(const AABB &p_rval) const { + return ((position != p_rval.position) || (size != p_rval.size)); +} + +bool AABB::create_from_points(const Vector &p_points) { + if (!p_points.size()) { + return false; + } + + Vector3 begin = p_points[0]; + Vector3 end = begin; + + for (int n = 1; n < p_points.size(); n++) { + const Vector3 &pt = p_points[n]; + + if (pt.x < begin.x) { + begin.x = pt.x; + } + if (pt.y < begin.y) { + begin.y = pt.y; + } + if (pt.z < begin.z) { + begin.z = pt.z; + } + + if (pt.x > end.x) { + end.x = pt.x; + } + if (pt.y > end.y) { + end.y = pt.y; + } + if (pt.z > end.z) { + end.z = pt.z; + } + } + + position = begin; + size = end - begin; + + return true; +} + +void AABB::merge_with(const AABB &p_aabb) { + Vector3 beg_1, beg_2; + Vector3 end_1, end_2; + Vector3 min, max; + + beg_1 = position; + beg_2 = p_aabb.position; + end_1 = Vector3(size.x, size.y, size.z) + beg_1; + end_2 = Vector3(p_aabb.size.x, p_aabb.size.y, p_aabb.size.z) + beg_2; + + min.x = (beg_1.x < beg_2.x) ? beg_1.x : beg_2.x; + min.y = (beg_1.y < beg_2.y) ? beg_1.y : beg_2.y; + min.z = (beg_1.z < beg_2.z) ? beg_1.z : beg_2.z; + + max.x = (end_1.x > end_2.x) ? end_1.x : end_2.x; + max.y = (end_1.y > end_2.y) ? end_1.y : end_2.y; + max.z = (end_1.z > end_2.z) ? end_1.z : end_2.z; + + position = min; + size = max - min; +} + +bool AABB::is_equal_approx(const AABB &p_aabb) const { + return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size); +} + +AABB AABB::intersection(const AABB &p_aabb) const { + Vector3 src_min = position; + Vector3 src_max = position + size; + Vector3 dst_min = p_aabb.position; + Vector3 dst_max = p_aabb.position + p_aabb.size; + + Vector3 min, max; + + if (src_min.x > dst_max.x || src_max.x < dst_min.x) { + return AABB(); + } else { + min.x = (src_min.x > dst_min.x) ? src_min.x : dst_min.x; + max.x = (src_max.x < dst_max.x) ? src_max.x : dst_max.x; + } + + if (src_min.y > dst_max.y || src_max.y < dst_min.y) { + return AABB(); + } else { + min.y = (src_min.y > dst_min.y) ? src_min.y : dst_min.y; + max.y = (src_max.y < dst_max.y) ? src_max.y : dst_max.y; + } + + if (src_min.z > dst_max.z || src_max.z < dst_min.z) { + return AABB(); + } else { + min.z = (src_min.z > dst_min.z) ? src_min.z : dst_min.z; + max.z = (src_max.z < dst_max.z) ? src_max.z : dst_max.z; + } + + return AABB(min, max - min); +} + +bool AABB::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip, Vector3 *r_normal) const { + Vector3 c1, c2; + Vector3 end = position + size; + // has a far and near macro defined, and we can't undo it here in the amalgamation + real_t aabb_near = -1e20; + real_t aabb_far = 1e20; + int axis = 0; + + for (int i = 0; i < 3; i++) { + if (p_dir[i] == 0) { + if ((p_from[i] < position[i]) || (p_from[i] > end[i])) { + return false; + } + } else { // ray not parallel to planes in this direction + c1[i] = (position[i] - p_from[i]) / p_dir[i]; + c2[i] = (end[i] - p_from[i]) / p_dir[i]; + + if (c1[i] > c2[i]) { + SWAP(c1, c2); + } + if (c1[i] > aabb_near) { + aabb_near = c1[i]; + axis = i; + } + if (c2[i] < aabb_far) { + aabb_far = c2[i]; + } + if ((aabb_near > aabb_far) || (aabb_far < 0)) { + return false; + } + } + } + + if (r_clip) { + *r_clip = c1; + } + if (r_normal) { + *r_normal = Vector3(); + (*r_normal)[axis] = p_dir[axis] ? -1 : 1; + } + + return true; +} + +bool AABB::intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip, Vector3 *r_normal) const { + real_t min = 0, max = 1; + int axis = 0; + real_t sign = 0; + + for (int i = 0; i < 3; i++) { + real_t seg_from = p_from[i]; + real_t seg_to = p_to[i]; + real_t box_begin = position[i]; + real_t box_end = box_begin + size[i]; + real_t cmin, cmax; + real_t csign; + + if (seg_from < seg_to) { + if (seg_from > box_end || seg_to < box_begin) { + return false; + } + real_t length = seg_to - seg_from; + cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0; + cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1; + csign = -1.0; + + } else { + if (seg_to > box_end || seg_from < box_begin) { + return false; + } + real_t length = seg_to - seg_from; + cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0; + cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1; + csign = 1.0; + } + + if (cmin > min) { + min = cmin; + axis = i; + sign = csign; + } + if (cmax < max) { + max = cmax; + } + if (max < min) { + return false; + } + } + + Vector3 rel = p_to - p_from; + + if (r_normal) { + Vector3 normal; + normal[axis] = sign; + *r_normal = normal; + } + + if (r_clip) { + *r_clip = p_from + rel * min; + } + + return true; +} + +bool AABB::intersects_plane(const Plane &p_plane) const { + Vector3 points[8] = { + Vector3(position.x, position.y, position.z), + Vector3(position.x, position.y, position.z + size.z), + Vector3(position.x, position.y + size.y, position.z), + Vector3(position.x, position.y + size.y, position.z + size.z), + Vector3(position.x + size.x, position.y, position.z), + Vector3(position.x + size.x, position.y, position.z + size.z), + Vector3(position.x + size.x, position.y + size.y, position.z), + Vector3(position.x + size.x, position.y + size.y, position.z + size.z), + }; + + bool over = false; + bool under = false; + + for (int i = 0; i < 8; i++) { + if (p_plane.distance_to(points[i]) > 0) { + over = true; + } else { + under = true; + } + } + + return under && over; +} + +Vector3 AABB::get_longest_axis() const { + Vector3 axis(1, 0, 0); + real_t max_size = size.x; + + if (size.y > max_size) { + axis = Vector3(0, 1, 0); + max_size = size.y; + } + + if (size.z > max_size) { + axis = Vector3(0, 0, 1); + } + + return axis; +} +int AABB::get_longest_axis_index() const { + int axis = 0; + real_t max_size = size.x; + + if (size.y > max_size) { + axis = 1; + max_size = size.y; + } + + if (size.z > max_size) { + axis = 2; + } + + return axis; +} + +Vector3 AABB::get_shortest_axis() const { + Vector3 axis(1, 0, 0); + real_t max_size = size.x; + + if (size.y < max_size) { + axis = Vector3(0, 1, 0); + max_size = size.y; + } + + if (size.z < max_size) { + axis = Vector3(0, 0, 1); + } + + return axis; +} +int AABB::get_shortest_axis_index() const { + int axis = 0; + real_t max_size = size.x; + + if (size.y < max_size) { + axis = 1; + max_size = size.y; + } + + if (size.z < max_size) { + axis = 2; + } + + return axis; +} + +AABB AABB::merge(const AABB &p_with) const { + AABB aabb = *this; + aabb.merge_with(p_with); + return aabb; +} +AABB AABB::expand(const Vector3 &p_vector) const { + AABB aabb = *this; + aabb.expand_to(p_vector); + return aabb; +} +AABB AABB::grow(real_t p_by) const { + AABB aabb = *this; + aabb.grow_by(p_by); + return aabb; +} + +void AABB::get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const { + ERR_FAIL_INDEX(p_edge, 12); + switch (p_edge) { + case 0: { + r_from = Vector3(position.x + size.x, position.y, position.z); + r_to = Vector3(position.x, position.y, position.z); + } break; + case 1: { + r_from = Vector3(position.x + size.x, position.y, position.z + size.z); + r_to = Vector3(position.x + size.x, position.y, position.z); + } break; + case 2: { + r_from = Vector3(position.x, position.y, position.z + size.z); + r_to = Vector3(position.x + size.x, position.y, position.z + size.z); + + } break; + case 3: { + r_from = Vector3(position.x, position.y, position.z); + r_to = Vector3(position.x, position.y, position.z + size.z); + + } break; + case 4: { + r_from = Vector3(position.x, position.y + size.y, position.z); + r_to = Vector3(position.x + size.x, position.y + size.y, position.z); + } break; + case 5: { + r_from = Vector3(position.x + size.x, position.y + size.y, position.z); + r_to = Vector3(position.x + size.x, position.y + size.y, position.z + size.z); + } break; + case 6: { + r_from = Vector3(position.x + size.x, position.y + size.y, position.z + size.z); + r_to = Vector3(position.x, position.y + size.y, position.z + size.z); + + } break; + case 7: { + r_from = Vector3(position.x, position.y + size.y, position.z + size.z); + r_to = Vector3(position.x, position.y + size.y, position.z); + + } break; + case 8: { + r_from = Vector3(position.x, position.y, position.z + size.z); + r_to = Vector3(position.x, position.y + size.y, position.z + size.z); + + } break; + case 9: { + r_from = Vector3(position.x, position.y, position.z); + r_to = Vector3(position.x, position.y + size.y, position.z); + + } break; + case 10: { + r_from = Vector3(position.x + size.x, position.y, position.z); + r_to = Vector3(position.x + size.x, position.y + size.y, position.z); + + } break; + case 11: { + r_from = Vector3(position.x + size.x, position.y, position.z + size.z); + r_to = Vector3(position.x + size.x, position.y + size.y, position.z + size.z); + + } break; + } +} + +/* +Variant AABB::intersects_segmentv(const Vector3 &p_from, const Vector3 &p_to) const { + Vector3 inters; + if (intersects_segment(p_from, p_to, &inters)) { + return inters; + } + return Variant(); +} + +Variant AABB::intersects_rayv(const Vector3 &p_from, const Vector3 &p_dir) const { + Vector3 inters; + if (intersects_ray(p_from, p_dir, &inters)) { + return inters; + } + return Variant(); +} +*/ + +AABB::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} +#line 0 + +#line 1 "sfw/core/vector3i.cpp" +/*************************************************************************/ +/* vector3i.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +void Vector3i::set_axis(const int p_axis, const int32_t p_value) { + ERR_FAIL_INDEX(p_axis, 3); + coord[p_axis] = p_value; +} + +int32_t Vector3i::get_axis(const int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 3, 0); + return operator[](p_axis); +} + +Vector3i::Axis Vector3i::min_axis() const { + return x < y ? (x < z ? Vector3i::AXIS_X : Vector3i::AXIS_Z) : (y < z ? Vector3i::AXIS_Y : Vector3i::AXIS_Z); +} + +Vector3i::Axis Vector3i::max_axis() const { + return x < y ? (y < z ? Vector3i::AXIS_Z : Vector3i::AXIS_Y) : (x < z ? Vector3i::AXIS_Z : Vector3i::AXIS_X); +} + +Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { + return Vector3i( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z)); +} + +Vector3 Vector3i::to_vector3() const { + return Vector3(x, y, z); +} + +Vector3i::operator String() const { + return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; +} + +Vector3i::operator Vector3() const { + return Vector3(x, y, z); +} +#line 0 + +#line 1 "sfw/core/transform_2d.cpp" +/*************************************************************************/ +/* transform_2d.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +void Transform2D::invert() { + // FIXME: this function assumes the basis is a rotation matrix, with no scaling. + // Transform2D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. + SWAP(columns[0][1], columns[1][0]); + columns[2] = basis_xform(-columns[2]); +} + +Transform2D Transform2D::inverse() const { + Transform2D inv = *this; + inv.invert(); + return inv; +} + +void Transform2D::affine_invert() { + real_t det = basis_determinant(); +#ifdef MATH_CHECKS + ERR_FAIL_COND(det == 0); +#endif + real_t idet = 1 / det; + + SWAP(columns[0][0], columns[1][1]); + columns[0] *= Vector2(idet, -idet); + columns[1] *= Vector2(-idet, idet); + + columns[2] = basis_xform(-columns[2]); +} + +Transform2D Transform2D::affine_inverse() const { + Transform2D inv = *this; + inv.affine_invert(); + return inv; +} + +void Transform2D::rotate(real_t p_phi) { + *this = Transform2D(p_phi, Vector2()) * (*this); +} + +real_t Transform2D::get_rotation() const { + return Math::atan2(columns[0].y, columns[0].x); +} + +void Transform2D::set_rotation(real_t p_rot) { + Size2 scale = get_scale(); + real_t cr = Math::cos(p_rot); + real_t sr = Math::sin(p_rot); + columns[0][0] = cr; + columns[0][1] = sr; + columns[1][0] = -sr; + columns[1][1] = cr; + set_scale(scale); +} + +real_t Transform2D::get_skew() const { + real_t det = basis_determinant(); + return Math::acos(columns[0].normalized().dot(SGN(det) * columns[1].normalized())) - (real_t)Math_PI * 0.5f; +} + +void Transform2D::set_skew(const real_t p_angle) { + real_t det = basis_determinant(); + columns[1] = SGN(det) * columns[0].rotated(((real_t)Math_PI * 0.5f + p_angle)).normalized() * columns[1].length(); +} + +Transform2D::Transform2D(real_t p_rot, const Vector2 &p_pos) { + real_t cr = Math::cos(p_rot); + real_t sr = Math::sin(p_rot); + columns[0][0] = cr; + columns[0][1] = sr; + columns[1][0] = -sr; + columns[1][1] = cr; + columns[2] = p_pos; +} + +Transform2D::Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos) { + columns[0][0] = Math::cos(p_rot) * p_scale.x; + columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; + columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; + columns[0][1] = Math::sin(p_rot) * p_scale.x; + columns[2] = p_pos; +} + +Size2 Transform2D::get_scale() const { + real_t det_sign = SGN(basis_determinant()); + return Size2(columns[0].length(), det_sign * columns[1].length()); +} + +void Transform2D::set_scale(const Size2 &p_scale) { + columns[0].normalize(); + columns[1].normalize(); + columns[0] *= p_scale.x; + columns[1] *= p_scale.y; +} + +void Transform2D::scale(const Size2 &p_scale) { + scale_basis(p_scale); + columns[2] *= p_scale; +} +void Transform2D::scale_basis(const Size2 &p_scale) { + columns[0][0] *= p_scale.x; + columns[0][1] *= p_scale.y; + columns[1][0] *= p_scale.x; + columns[1][1] *= p_scale.y; +} + +void Transform2D::translate(real_t p_tx, real_t p_ty) { + translate(Vector2(p_tx, p_ty)); +} +void Transform2D::translate(const Vector2 &p_offset) { + columns[2] += p_offset; +} + +void Transform2D::translate_local(real_t p_tx, real_t p_ty) { + translate_local(Vector2(p_tx, p_ty)); +} +void Transform2D::translate_local(const Vector2 &p_translation) { + columns[2] += basis_xform(p_translation); +} + +void Transform2D::translater(real_t p_tx, real_t p_ty) { + translate(Vector2(p_tx, p_ty)); +} +void Transform2D::translatev(const Vector2 &p_offset) { + columns[2] += p_offset; +} + +void Transform2D::translate_localr(real_t p_tx, real_t p_ty) { + translate_local(Vector2(p_tx, p_ty)); +} +void Transform2D::translate_localv(const Vector2 &p_translation) { + columns[2] += basis_xform(p_translation); +} + +void Transform2D::orthonormalize() { + // Gram-Schmidt Process + + Vector2 x = columns[0]; + Vector2 y = columns[1]; + + x.normalize(); + y = (y - x * (x.dot(y))); + y.normalize(); + + columns[0] = x; + columns[1] = y; +} + +Transform2D Transform2D::orthonormalized() const { + Transform2D on = *this; + on.orthonormalize(); + return on; +} + +bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { + return columns[0].is_equal_approx(p_transform.columns[0]) && columns[1].is_equal_approx(p_transform.columns[1]) && columns[2].is_equal_approx(p_transform.columns[2]); +} + +Transform2D Transform2D::looking_at(const Vector2 &p_target) const { + Transform2D return_trans = Transform2D(get_rotation(), get_origin()); + Vector2 target_position = affine_inverse().xform(p_target); + return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle()); + return return_trans; +} + +bool Transform2D::operator==(const Transform2D &p_transform) const { + for (int i = 0; i < 3; i++) { + if (columns[i] != p_transform.columns[i]) { + return false; + } + } + + return true; +} + +bool Transform2D::operator!=(const Transform2D &p_transform) const { + for (int i = 0; i < 3; i++) { + if (columns[i] != p_transform.columns[i]) { + return true; + } + } + + return false; +} + +void Transform2D::operator*=(const Transform2D &p_transform) { + columns[2] = xform(p_transform.columns[2]); + + real_t x0, x1, y0, y1; + + x0 = tdotx(p_transform.columns[0]); + x1 = tdoty(p_transform.columns[0]); + y0 = tdotx(p_transform.columns[1]); + y1 = tdoty(p_transform.columns[1]); + + columns[0][0] = x0; + columns[0][1] = x1; + columns[1][0] = y0; + columns[1][1] = y1; +} + +Transform2D Transform2D::operator*(const Transform2D &p_transform) const { + Transform2D t = *this; + t *= p_transform; + return t; +} + +void Transform2D::operator*=(const real_t p_val) { + columns[0] *= p_val; + columns[1] *= p_val; + columns[2] *= p_val; +} + +Transform2D Transform2D::operator*(const real_t p_val) const { + Transform2D ret(*this); + ret *= p_val; + return ret; +} + +Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const { + Transform2D copy = *this; + copy.scale_basis(p_scale); + return copy; +} + +Transform2D Transform2D::scaled(const Size2 &p_scale) const { + // Equivalent to left multiplication + Transform2D copy = *this; + copy.scale(p_scale); + return copy; +} + +Transform2D Transform2D::scaled_local(const Size2 &p_scale) const { + // Equivalent to right multiplication + return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]); +} + +Transform2D Transform2D::untranslated() const { + Transform2D copy = *this; + copy.columns[2] = Vector2(); + return copy; +} + +Transform2D Transform2D::translated(const Vector2 &p_offset) const { + // Equivalent to left multiplication + return Transform2D(columns[0], columns[1], columns[2] + p_offset); +} + +Transform2D Transform2D::translated_local(const Vector2 &p_offset) const { + // Equivalent to right multiplication + return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset)); +} + +Transform2D Transform2D::rotated(const real_t p_angle) const { + // Equivalent to left multiplication + return Transform2D(p_angle, Vector2()) * (*this); +} + +Transform2D Transform2D::rotated_local(const real_t p_angle) const { + // Equivalent to right multiplication + return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped. +} + +real_t Transform2D::basis_determinant() const { + return columns[0].x * columns[1].y - columns[0].y * columns[1].x; +} + +Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t p_c) const { + //extract parameters + Vector2 p1 = get_origin(); + Vector2 p2 = p_transform.get_origin(); + + real_t r1 = get_rotation(); + real_t r2 = p_transform.get_rotation(); + + Size2 s1 = get_scale(); + Size2 s2 = p_transform.get_scale(); + + //slerp rotation + Vector2 v1(Math::cos(r1), Math::sin(r1)); + Vector2 v2(Math::cos(r2), Math::sin(r2)); + + real_t dot = v1.dot(v2); + + dot = CLAMP(dot, -1, 1); + + Vector2 v; + + if (dot > 0.9995f) { + v = Vector2::linear_interpolate(v1, v2, p_c).normalized(); //linearly interpolate to avoid numerical precision issues + } else { + real_t angle = p_c * Math::acos(dot); + Vector2 v3 = (v2 - v1 * dot).normalized(); + v = v1 * Math::cos(angle) + v3 * Math::sin(angle); + } + + //construct matrix + Transform2D res(Math::atan2(v.y, v.x), Vector2::linear_interpolate(p1, p2, p_c)); + res.scale_basis(Vector2::linear_interpolate(s1, s2, p_c)); + return res; +} + +Transform2D::operator String() const { + return "[X: " + columns[0].operator String() + + ", Y: " + columns[1].operator String() + + ", O: " + columns[2].operator String() + "]"; +} +#line 0 + +#line 1 "sfw/core/projection.cpp" +/*************************************************************************/ +/* projection.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +float Projection::determinant() const { + return matrix[0][3] * matrix[1][2] * matrix[2][1] * matrix[3][0] - matrix[0][2] * matrix[1][3] * matrix[2][1] * matrix[3][0] - + matrix[0][3] * matrix[1][1] * matrix[2][2] * matrix[3][0] + matrix[0][1] * matrix[1][3] * matrix[2][2] * matrix[3][0] + + matrix[0][2] * matrix[1][1] * matrix[2][3] * matrix[3][0] - matrix[0][1] * matrix[1][2] * matrix[2][3] * matrix[3][0] - + matrix[0][3] * matrix[1][2] * matrix[2][0] * matrix[3][1] + matrix[0][2] * matrix[1][3] * matrix[2][0] * matrix[3][1] + + matrix[0][3] * matrix[1][0] * matrix[2][2] * matrix[3][1] - matrix[0][0] * matrix[1][3] * matrix[2][2] * matrix[3][1] - + matrix[0][2] * matrix[1][0] * matrix[2][3] * matrix[3][1] + matrix[0][0] * matrix[1][2] * matrix[2][3] * matrix[3][1] + + matrix[0][3] * matrix[1][1] * matrix[2][0] * matrix[3][2] - matrix[0][1] * matrix[1][3] * matrix[2][0] * matrix[3][2] - + matrix[0][3] * matrix[1][0] * matrix[2][1] * matrix[3][2] + matrix[0][0] * matrix[1][3] * matrix[2][1] * matrix[3][2] + + matrix[0][1] * matrix[1][0] * matrix[2][3] * matrix[3][2] - matrix[0][0] * matrix[1][1] * matrix[2][3] * matrix[3][2] - + matrix[0][2] * matrix[1][1] * matrix[2][0] * matrix[3][3] + matrix[0][1] * matrix[1][2] * matrix[2][0] * matrix[3][3] + + matrix[0][2] * matrix[1][0] * matrix[2][1] * matrix[3][3] - matrix[0][0] * matrix[1][2] * matrix[2][1] * matrix[3][3] - + matrix[0][1] * matrix[1][0] * matrix[2][2] * matrix[3][3] + matrix[0][0] * matrix[1][1] * matrix[2][2] * matrix[3][3]; +} + +void Projection::set_identity() { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + matrix[i][j] = (i == j) ? 1 : 0; + } + } +} + +void Projection::set_zero() { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + matrix[i][j] = 0; + } + } +} + +void Projection::adjust_perspective_znear(real_t p_new_znear) { + real_t zfar = get_z_far(); + real_t znear = p_new_znear; + + real_t deltaZ = zfar - znear; + matrix[2][2] = -(zfar + znear) / deltaZ; + matrix[3][2] = -2 * znear * zfar / deltaZ; +} + +Projection Projection::create_depth_correction(bool p_flip_y) { + Projection proj; + proj.set_depth_correction(p_flip_y); + return proj; +} + +Projection Projection::create_light_atlas_rect(const Rect2 &p_rect) { + Projection proj; + proj.set_light_atlas_rect(p_rect); + return proj; +} + +Projection Projection::create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) { + Projection proj; + proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov); + return proj; +} + +Projection Projection::create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { + Projection proj; + proj.set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov, p_eye, p_intraocular_dist, p_convergence_dist); + return proj; +} + +Projection Projection::create_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) { + Projection proj; + proj.set_for_hmd(p_eye, p_aspect, p_intraocular_dist, p_display_width, p_display_to_lens, p_oversample, p_z_near, p_z_far); + return proj; +} + +Projection Projection::create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { + Projection proj; + proj.set_orthogonal(p_left, p_right, p_bottom, p_top, p_zfar, p_zfar); + return proj; +} + +Projection Projection::create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) { + Projection proj; + proj.set_orthogonal(p_size, p_aspect, p_znear, p_zfar, p_flip_fov); + return proj; +} + +Projection Projection::create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { + Projection proj; + proj.set_frustum(p_left, p_right, p_bottom, p_top, p_near, p_far); + return proj; +} + +Projection Projection::create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { + Projection proj; + proj.set_frustum(p_size, p_aspect, p_offset, p_near, p_far, p_flip_fov); + return proj; +} + +Projection Projection::create_fit_aabb(const AABB &p_aabb) { + Projection proj; + proj.scale_translate_to_fit(p_aabb); + return proj; +} + +Projection Projection::perspective_znear_adjusted(real_t p_new_znear) const { + Projection proj = *this; + proj.adjust_perspective_znear(p_new_znear); + return proj; +} + +Plane Projection::get_projection_plane(Projection::Planes p_plane) const { + const real_t *matrix = (const real_t *)this->matrix; + + switch (p_plane) { + case PLANE_NEAR: { + Plane new_plane = Plane(matrix[3] + matrix[2], + matrix[7] + matrix[6], + matrix[11] + matrix[10], + matrix[15] + matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_FAR: { + Plane new_plane = Plane(matrix[3] - matrix[2], + matrix[7] - matrix[6], + matrix[11] - matrix[10], + matrix[15] - matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_LEFT: { + Plane new_plane = Plane(matrix[3] + matrix[0], + matrix[7] + matrix[4], + matrix[11] + matrix[8], + matrix[15] + matrix[12]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_TOP: { + Plane new_plane = Plane(matrix[3] - matrix[1], + matrix[7] - matrix[5], + matrix[11] - matrix[9], + matrix[15] - matrix[13]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_RIGHT: { + Plane new_plane = Plane(matrix[3] - matrix[0], + matrix[7] - matrix[4], + matrix[11] - matrix[8], + matrix[15] - matrix[12]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + case PLANE_BOTTOM: { + Plane new_plane = Plane(matrix[3] + matrix[1], + matrix[7] + matrix[5], + matrix[11] + matrix[9], + matrix[15] + matrix[13]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + return new_plane; + } break; + } + + return Plane(); +} + +Projection Projection::flipped_y() const { + Projection proj = *this; + proj.flip_y(); + return proj; +} + +Projection Projection ::jitter_offseted(const Vector2 &p_offset) const { + Projection proj = *this; + proj.add_jitter_offset(p_offset); + return proj; +} + +void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov) { + if (p_flip_fov) { + p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect); + } + + real_t sine, cotangent, deltaZ; + real_t radians = Math::deg2rad(p_fovy_degrees / 2.0); + + deltaZ = p_z_far - p_z_near; + sine = Math::sin(radians); + + if ((deltaZ == 0) || (sine == 0) || (p_aspect == 0)) { + return; + } + cotangent = Math::cos(radians) / sine; + + set_identity(); + + matrix[0][0] = cotangent / p_aspect; + matrix[1][1] = cotangent; + matrix[2][2] = -(p_z_far + p_z_near) / deltaZ; + matrix[2][3] = -1; + matrix[3][2] = -2 * p_z_near * p_z_far / deltaZ; + matrix[3][3] = 0; +} + +void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { + if (p_flip_fov) { + p_fovy_degrees = get_fovy(p_fovy_degrees, 1.0 / p_aspect); + } + + real_t left, right, modeltranslation, ymax, xmax, frustumshift; + + ymax = p_z_near * tan(Math::deg2rad(p_fovy_degrees / 2.0)); + xmax = ymax * p_aspect; + frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist; + + switch (p_eye) { + case 1: { // left eye + left = -xmax + frustumshift; + right = xmax + frustumshift; + modeltranslation = p_intraocular_dist / 2.0; + } break; + case 2: { // right eye + left = -xmax - frustumshift; + right = xmax - frustumshift; + modeltranslation = -p_intraocular_dist / 2.0; + } break; + default: { // mono, should give the same result as set_perspective(p_fovy_degrees,p_aspect,p_z_near,p_z_far,p_flip_fov) + left = -xmax; + right = xmax; + modeltranslation = 0.0; + } break; + } + + set_frustum(left, right, -ymax, ymax, p_z_near, p_z_far); + + // translate matrix by (modeltranslation, 0.0, 0.0) + Projection cm; + cm.set_identity(); + cm.matrix[3][0] = modeltranslation; + *this = *this * cm; +} + +void Projection::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 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; + + // now we apply our oversample factor to increase our FOV. how much we oversample is always a balance we strike between performance and how much + // we're willing to sacrifice in FOV. + real_t add = ((f1 + f2) * (p_oversample - 1.0)) / 2.0; + f1 += add; + f2 += add; + f3 *= p_oversample; + + // always apply KEEP_WIDTH aspect ratio + f3 /= p_aspect; + + switch (p_eye) { + case 1: { // left eye + set_frustum(-f2 * p_z_near, f1 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far); + } break; + case 2: { // right eye + set_frustum(-f1 * p_z_near, f2 * p_z_near, -f3 * p_z_near, f3 * p_z_near, p_z_near, p_z_far); + } break; + default: { // mono, does not apply here! + } break; + } +} + +void Projection::set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { + set_identity(); + + matrix[0][0] = 2.0 / (p_right - p_left); + matrix[3][0] = -((p_right + p_left) / (p_right - p_left)); + matrix[1][1] = 2.0 / (p_top - p_bottom); + matrix[3][1] = -((p_top + p_bottom) / (p_top - p_bottom)); + matrix[2][2] = -2.0 / (p_zfar - p_znear); + matrix[3][2] = -((p_zfar + p_znear) / (p_zfar - p_znear)); + matrix[3][3] = 1.0; +} + +void Projection::set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov) { + if (!p_flip_fov) { + p_size *= p_aspect; + } + + set_orthogonal(-p_size / 2, +p_size / 2, -p_size / p_aspect / 2, +p_size / p_aspect / 2, p_znear, p_zfar); +} + +void Projection::set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { + ERR_FAIL_COND(p_right <= p_left); + ERR_FAIL_COND(p_top <= p_bottom); + ERR_FAIL_COND(p_far <= p_near); + + real_t *te = &matrix[0][0]; + real_t x = 2 * p_near / (p_right - p_left); + real_t y = 2 * p_near / (p_top - p_bottom); + + real_t a = (p_right + p_left) / (p_right - p_left); + real_t b = (p_top + p_bottom) / (p_top - p_bottom); + real_t c = -(p_far + p_near) / (p_far - p_near); + real_t d = -2 * p_far * p_near / (p_far - p_near); + + te[0] = x; + te[1] = 0; + te[2] = 0; + te[3] = 0; + te[4] = 0; + te[5] = y; + te[6] = 0; + te[7] = 0; + te[8] = a; + te[9] = b; + te[10] = c; + te[11] = -1; + te[12] = 0; + te[13] = 0; + te[14] = d; + te[15] = 0; +} + +void Projection::set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { + if (!p_flip_fov) { + p_size *= p_aspect; + } + + set_frustum(-p_size / 2 + p_offset.x, +p_size / 2 + p_offset.x, -p_size / p_aspect / 2 + p_offset.y, +p_size / p_aspect / 2 + p_offset.y, p_near, p_far); +} + +real_t Projection::get_z_far() const { + const real_t *matrix = (const real_t *)this->matrix; + Plane new_plane = Plane(matrix[3] - matrix[2], + matrix[7] - matrix[6], + matrix[11] - matrix[10], + matrix[15] - matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + return new_plane.d; +} + +real_t Projection::get_z_near() const { + const real_t *matrix = (const real_t *)this->matrix; + Plane new_plane = Plane(matrix[3] + matrix[2], + matrix[7] + matrix[6], + matrix[11] + matrix[10], + -matrix[15] - matrix[14]); + + new_plane.normalize(); + return new_plane.d; +} + +Vector2 Projection::get_viewport_half_extents() const { + const real_t *matrix = (const real_t *)this->matrix; + ///////--- Near Plane ---/////// + Plane near_plane = Plane(matrix[3] + matrix[2], + matrix[7] + matrix[6], + matrix[11] + matrix[10], + -matrix[15] - matrix[14]); + near_plane.normalize(); + + ///////--- Right Plane ---/////// + Plane right_plane = Plane(matrix[3] - matrix[0], + matrix[7] - matrix[4], + matrix[11] - matrix[8], + -matrix[15] + matrix[12]); + right_plane.normalize(); + + Plane top_plane = Plane(matrix[3] - matrix[1], + matrix[7] - matrix[5], + matrix[11] - matrix[9], + -matrix[15] + matrix[13]); + top_plane.normalize(); + + Vector3 res; + near_plane.intersect_3(right_plane, top_plane, &res); + + return Vector2(res.x, res.y); +} + +Vector2 Projection::get_far_plane_half_extents() const { + const real_t *matrix = (const real_t *)this->matrix; + ///////--- Far Plane ---/////// + Plane far_plane = Plane(matrix[3] - matrix[2], + matrix[7] - matrix[6], + matrix[11] - matrix[10], + -matrix[15] + matrix[14]); + far_plane.normalize(); + + ///////--- Right Plane ---/////// + Plane right_plane = Plane(matrix[3] - matrix[0], + matrix[7] - matrix[4], + matrix[11] - matrix[8], + -matrix[15] + matrix[12]); + right_plane.normalize(); + + Plane top_plane = Plane(matrix[3] - matrix[1], + matrix[7] - matrix[5], + matrix[11] - matrix[9], + -matrix[15] + matrix[13]); + top_plane.normalize(); + + Vector3 res; + far_plane.intersect_3(right_plane, top_plane, &res); + + return Vector2(res.x, res.y); +} + +bool Projection::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const { + Vector planes = get_projection_planes(Transform()); + const Planes intersections[8][3] = { + { PLANE_FAR, PLANE_LEFT, PLANE_TOP }, + { PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM }, + { PLANE_FAR, PLANE_RIGHT, PLANE_TOP }, + { PLANE_FAR, PLANE_RIGHT, PLANE_BOTTOM }, + { PLANE_NEAR, PLANE_LEFT, PLANE_TOP }, + { PLANE_NEAR, PLANE_LEFT, PLANE_BOTTOM }, + { PLANE_NEAR, PLANE_RIGHT, PLANE_TOP }, + { PLANE_NEAR, PLANE_RIGHT, PLANE_BOTTOM }, + }; + + for (int i = 0; i < 8; i++) { + Vector3 point; + bool res = planes[intersections[i][0]].intersect_3(planes[intersections[i][1]], planes[intersections[i][2]], &point); + ERR_FAIL_COND_V(!res, false); + p_8points[i] = p_transform.xform(point); + } + + return true; +} + +Vector Projection::get_projection_planes(const Transform &p_transform) const { + /** Fast Plane Extraction from combined modelview/projection matrices. + * References: + * https://web.archive.org/web/20011221205252/https://www.markmorley.com/opengl/frustumculling.html + * https://web.archive.org/web/20061020020112/https://www2.ravensoft.com/users/ggribb/plane%20extraction.pdf + */ + + Vector planes; + planes.resize(6); + + const real_t *matrix = (const real_t *)this->matrix; + + Plane new_plane; + + ///////--- Near Plane ---/////// + new_plane = Plane(matrix[3] + matrix[2], + matrix[7] + matrix[6], + matrix[11] + matrix[10], + matrix[15] + matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + planes.write[0] = p_transform.xform(new_plane); + + ///////--- Far Plane ---/////// + new_plane = Plane(matrix[3] - matrix[2], + matrix[7] - matrix[6], + matrix[11] - matrix[10], + matrix[15] - matrix[14]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + planes.write[1] = p_transform.xform(new_plane); + + ///////--- Left Plane ---/////// + new_plane = Plane(matrix[3] + matrix[0], + matrix[7] + matrix[4], + matrix[11] + matrix[8], + matrix[15] + matrix[12]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + planes.write[2] = p_transform.xform(new_plane); + + ///////--- Top Plane ---/////// + new_plane = Plane(matrix[3] - matrix[1], + matrix[7] - matrix[5], + matrix[11] - matrix[9], + matrix[15] - matrix[13]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + planes.write[3] = p_transform.xform(new_plane); + + ///////--- Right Plane ---/////// + new_plane = Plane(matrix[3] - matrix[0], + matrix[7] - matrix[4], + matrix[11] - matrix[8], + matrix[15] - matrix[12]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + planes.write[4] = p_transform.xform(new_plane); + + ///////--- Bottom Plane ---/////// + new_plane = Plane(matrix[3] + matrix[1], + matrix[7] + matrix[5], + matrix[11] + matrix[9], + matrix[15] + matrix[13]); + + new_plane.normal = -new_plane.normal; + new_plane.normalize(); + + planes.write[5] = p_transform.xform(new_plane); + + return planes; +} + +Projection Projection::inverse() const { + Projection cm = *this; + cm.invert(); + return cm; +} + +void Projection::invert() { + int i, j, k; + int pvt_i[4], pvt_j[4]; /* Locations of pivot matrix */ + real_t pvt_val; /* Value of current pivot element */ + real_t hold; /* Temporary storage */ + real_t determinant = 1.0f; + for (k = 0; k < 4; k++) { + /** Locate k'th pivot element **/ + pvt_val = matrix[k][k]; /** Initialize for search **/ + pvt_i[k] = k; + pvt_j[k] = k; + for (i = k; i < 4; i++) { + for (j = k; j < 4; j++) { + if (Math::abs(matrix[i][j]) > Math::abs(pvt_val)) { + pvt_i[k] = i; + pvt_j[k] = j; + pvt_val = matrix[i][j]; + } + } + } + + /** Product of pivots, gives determinant when finished **/ + determinant *= pvt_val; + if (Math::is_zero_approx(determinant)) { + return; /** Matrix is singular (zero determinant). **/ + } + + /** "Interchange" rows (with sign change stuff) **/ + i = pvt_i[k]; + if (i != k) { /** If rows are different **/ + for (j = 0; j < 4; j++) { + hold = -matrix[k][j]; + matrix[k][j] = matrix[i][j]; + matrix[i][j] = hold; + } + } + + /** "Interchange" columns **/ + j = pvt_j[k]; + if (j != k) { /** If columns are different **/ + for (i = 0; i < 4; i++) { + hold = -matrix[i][k]; + matrix[i][k] = matrix[i][j]; + matrix[i][j] = hold; + } + } + + /** Divide column by minus pivot value **/ + for (i = 0; i < 4; i++) { + if (i != k) { + matrix[i][k] /= (-pvt_val); + } + } + + /** Reduce the matrix **/ + for (i = 0; i < 4; i++) { + hold = matrix[i][k]; + for (j = 0; j < 4; j++) { + if (i != k && j != k) { + matrix[i][j] += hold * matrix[k][j]; + } + } + } + + /** Divide row by pivot **/ + for (j = 0; j < 4; j++) { + if (j != k) { + matrix[k][j] /= pvt_val; + } + } + + /** Replace pivot by reciprocal (at last we can touch it). **/ + matrix[k][k] = 1.0 / pvt_val; + } + + /* That was most of the work, one final pass of row/column interchange */ + /* to finish */ + for (k = 4 - 2; k >= 0; k--) { /* Don't need to work with 1 by 1 corner*/ + i = pvt_j[k]; /* Rows to swap correspond to pivot COLUMN */ + if (i != k) { /* If rows are different */ + for (j = 0; j < 4; j++) { + hold = matrix[k][j]; + matrix[k][j] = -matrix[i][j]; + matrix[i][j] = hold; + } + } + + j = pvt_i[k]; /* Columns to swap correspond to pivot ROW */ + if (j != k) { /* If columns are different */ + for (i = 0; i < 4; i++) { + hold = matrix[i][k]; + matrix[i][k] = -matrix[i][j]; + matrix[i][j] = hold; + } + } + } +} + +void Projection::flip_y() { + for (int i = 0; i < 4; i++) { + matrix[1][i] = -matrix[1][i]; + } +} + +Projection::Projection() { + set_identity(); +} + +Projection Projection::operator*(const Projection &p_matrix) const { + Projection new_matrix; + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + real_t ab = 0; + for (int k = 0; k < 4; k++) { + ab += matrix[k][i] * p_matrix.matrix[j][k]; + } + new_matrix.matrix[j][i] = ab; + } + } + + return new_matrix; +} + +void Projection::set_depth_correction(bool p_flip_y) { + real_t *m = &matrix[0][0]; + + m[0] = 1; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + m[4] = 0.0; + m[5] = p_flip_y ? -1 : 1; + m[6] = 0.0; + m[7] = 0.0; + m[8] = 0.0; + m[9] = 0.0; + m[10] = 0.5; + m[11] = 0.0; + m[12] = 0.0; + m[13] = 0.0; + m[14] = 0.5; + m[15] = 1.0; +} + +void Projection::set_light_bias() { + real_t *m = &matrix[0][0]; + + m[0] = 0.5; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + m[4] = 0.0; + m[5] = 0.5; + m[6] = 0.0; + m[7] = 0.0; + m[8] = 0.0; + m[9] = 0.0; + m[10] = 0.5; + m[11] = 0.0; + m[12] = 0.5; + m[13] = 0.5; + m[14] = 0.5; + m[15] = 1.0; +} + +void Projection::set_light_atlas_rect(const Rect2 &p_rect) { + real_t *m = &matrix[0][0]; + + m[0] = p_rect.size.width; + m[1] = 0.0; + m[2] = 0.0; + m[3] = 0.0; + m[4] = 0.0; + m[5] = p_rect.size.height; + m[6] = 0.0; + m[7] = 0.0; + m[8] = 0.0; + m[9] = 0.0; + m[10] = 1.0; + m[11] = 0.0; + m[12] = p_rect.position.x; + m[13] = p_rect.position.y; + m[14] = 0.0; + m[15] = 1.0; +} + +Vector4 Projection::xform(const Vector4 &p_vec4) const { + return Vector4( + matrix[0][0] * p_vec4.x + matrix[1][0] * p_vec4.y + matrix[2][0] * p_vec4.z + matrix[3][0] * p_vec4.w, + matrix[0][1] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[2][1] * p_vec4.z + matrix[3][1] * p_vec4.w, + matrix[0][2] * p_vec4.x + matrix[1][2] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[3][2] * p_vec4.w, + matrix[0][3] * p_vec4.x + matrix[1][3] * p_vec4.y + matrix[2][3] * p_vec4.z + matrix[3][3] * p_vec4.w); +} + +Vector4 Projection::xform_inv(const Vector4 &p_vec4) const { + return Vector4( + matrix[0][0] * p_vec4.x + matrix[0][1] * p_vec4.y + matrix[0][2] * p_vec4.z + matrix[0][3] * p_vec4.w, + matrix[1][0] * p_vec4.x + matrix[1][1] * p_vec4.y + matrix[1][2] * p_vec4.z + matrix[1][3] * p_vec4.w, + matrix[2][0] * p_vec4.x + matrix[2][1] * p_vec4.y + matrix[2][2] * p_vec4.z + matrix[2][3] * p_vec4.w, + matrix[3][0] * p_vec4.x + matrix[3][1] * p_vec4.y + matrix[3][2] * p_vec4.z + matrix[3][3] * p_vec4.w); +} + +Plane Projection::xform(const Plane &p_vec4) const { + Plane ret; + + ret.normal.x = matrix[0][0] * p_vec4.normal.x + matrix[1][0] * p_vec4.normal.y + matrix[2][0] * p_vec4.normal.z + matrix[3][0] * p_vec4.d; + ret.normal.y = matrix[0][1] * p_vec4.normal.x + matrix[1][1] * p_vec4.normal.y + matrix[2][1] * p_vec4.normal.z + matrix[3][1] * p_vec4.d; + ret.normal.z = matrix[0][2] * p_vec4.normal.x + matrix[1][2] * p_vec4.normal.y + matrix[2][2] * p_vec4.normal.z + matrix[3][2] * p_vec4.d; + ret.d = matrix[0][3] * p_vec4.normal.x + matrix[1][3] * p_vec4.normal.y + matrix[2][3] * p_vec4.normal.z + matrix[3][3] * p_vec4.d; + return ret; +} + +Projection::operator String() const { + return "[ X: " + matrix[0].operator String() + + ", Y: " + matrix[1].operator String() + + ", Z: " + matrix[2].operator String() + + ", W: " + matrix[3].operator String() + " ]"; +} + +real_t Projection::get_aspect() const { + Vector2 vp_he = get_viewport_half_extents(); + return vp_he.x / vp_he.y; +} + +int Projection::get_pixels_per_meter(int p_for_pixel_width) const { + Vector3 result = xform(Vector3(1, 0, -1)); + + return int((result.x * 0.5 + 0.5) * p_for_pixel_width); +} + +bool Projection::is_orthogonal() const { + return matrix[3][3] == 1.0; +} + +real_t Projection::get_fov() const { + const real_t *matrix = (const real_t *)this->matrix; + + Plane right_plane = Plane(matrix[3] - matrix[0], + matrix[7] - matrix[4], + matrix[11] - matrix[8], + -matrix[15] + matrix[12]); + right_plane.normalize(); + + if ((matrix[8] == 0) && (matrix[9] == 0)) { + return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0; + } else { + // 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], + matrix[15] + matrix[12]); + left_plane.normalize(); + + return Math::rad2deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))); + } +} + +float Projection::get_lod_multiplier() const { + if (is_orthogonal()) { + return get_viewport_half_extents().x; + } else { + float zn = get_z_near(); + float width = get_viewport_half_extents().x * 2.0; + return 1.0 / (zn / width); + } + + //usage is lod_size / (lod_distance * multiplier) < threshold +} +void Projection::make_scale(const Vector3 &p_scale) { + set_identity(); + matrix[0][0] = p_scale.x; + matrix[1][1] = p_scale.y; + matrix[2][2] = p_scale.z; +} + +void Projection::scale_translate_to_fit(const AABB &p_aabb) { + Vector3 min = p_aabb.position; + Vector3 max = p_aabb.position + p_aabb.size; + + matrix[0][0] = 2 / (max.x - min.x); + matrix[1][0] = 0; + matrix[2][0] = 0; + matrix[3][0] = -(max.x + min.x) / (max.x - min.x); + + matrix[0][1] = 0; + matrix[1][1] = 2 / (max.y - min.y); + matrix[2][1] = 0; + matrix[3][1] = -(max.y + min.y) / (max.y - min.y); + + matrix[0][2] = 0; + matrix[1][2] = 0; + matrix[2][2] = 2 / (max.z - min.z); + matrix[3][2] = -(max.z + min.z) / (max.z - min.z); + + matrix[0][3] = 0; + matrix[1][3] = 0; + matrix[2][3] = 0; + matrix[3][3] = 1; +} + +void Projection::add_jitter_offset(const Vector2 &p_offset) { + matrix[3][0] += p_offset.x; + matrix[3][1] += p_offset.y; +} + +Projection::operator Transform() const { + Transform tr; + const real_t *m = &matrix[0][0]; + + tr.basis.rows[0][0] = m[0]; + tr.basis.rows[1][0] = m[1]; + tr.basis.rows[2][0] = m[2]; + + tr.basis.rows[0][1] = m[4]; + tr.basis.rows[1][1] = m[5]; + tr.basis.rows[2][1] = m[6]; + + tr.basis.rows[0][2] = m[8]; + tr.basis.rows[1][2] = m[9]; + tr.basis.rows[2][2] = m[10]; + + tr.origin.x = m[12]; + tr.origin.y = m[13]; + tr.origin.z = m[14]; + + return tr; +} + +void Projection::set_frustum2(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov) { + set_frustum(p_size, p_aspect, p_offset, p_near, p_far, p_flip_fov); +} + +Projection::Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w) { + matrix[0] = p_x; + matrix[1] = p_y; + matrix[2] = p_z; + matrix[3] = p_w; +} +Projection::Projection(const Transform &p_transform) { + const Transform &tr = p_transform; + real_t *m = &matrix[0][0]; + + m[0] = tr.basis.rows[0][0]; + m[1] = tr.basis.rows[1][0]; + m[2] = tr.basis.rows[2][0]; + m[3] = 0.0; + m[4] = tr.basis.rows[0][1]; + m[5] = tr.basis.rows[1][1]; + m[6] = tr.basis.rows[2][1]; + m[7] = 0.0; + m[8] = tr.basis.rows[0][2]; + m[9] = tr.basis.rows[1][2]; + m[10] = tr.basis.rows[2][2]; + m[11] = 0.0; + m[12] = tr.origin.x; + m[13] = tr.origin.y; + m[14] = tr.origin.z; + m[15] = 1.0; +} + +Projection::~Projection() { +} +#line 0 + +#line 1 "sfw/core/vector3.cpp" +/*************************************************************************/ +/* vector3.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +void Vector3::rotate(const Vector3 &p_axis, real_t p_phi) { + *this = Basis(p_axis, p_phi).xform(*this); +} + +Vector3 Vector3::rotated(const Vector3 &p_axis, real_t p_phi) const { + Vector3 r = *this; + r.rotate(p_axis, p_phi); + return r; +} + +void Vector3::set_axis(int p_axis, real_t p_value) { + ERR_FAIL_INDEX(p_axis, 3); + coord[p_axis] = p_value; +} +real_t Vector3::get_axis(int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 3, 0); + return operator[](p_axis); +} + +void Vector3::snap(const Vector3 &p_val) { + x = Math::stepify(x, p_val.x); + y = Math::stepify(y, p_val.y); + z = Math::stepify(z, p_val.z); +} +Vector3 Vector3::snapped(const Vector3 &p_val) const { + Vector3 v = *this; + v.snap(p_val); + return v; +} + +Vector3 Vector3::limit_length(const real_t p_len) const { + const real_t l = length(); + Vector3 v = *this; + if (l > 0 && p_len < l) { + v /= l; + v *= p_len; + } + + return v; +} + +Vector3 Vector3::move_toward(const Vector3 &p_to, const real_t p_delta) const { + Vector3 v = *this; + Vector3 vd = p_to - v; + real_t len = vd.length(); + return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta; +} + +Basis Vector3::outer(const Vector3 &p_b) const { + Vector3 row0(x * p_b.x, x * p_b.y, x * p_b.z); + Vector3 row1(y * p_b.x, y * p_b.y, y * p_b.z); + Vector3 row2(z * p_b.x, z * p_b.y, z * p_b.z); + + return Basis(row0, row1, row2); +} + +Basis Vector3::to_diagonal_matrix() const { + return Basis(x, 0, 0, + 0, y, 0, + 0, 0, z); +} + +Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const { + return Vector3( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z)); +} + +bool Vector3::is_equal_approx(const Vector3 &p_v) const { + return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z); +} + +Vector3::operator String() const { + return "(" + String::num_real(x) + ", " + String::num_real(y) + ", " + String::num_real(z) + ")"; +} +#line 0 + +#line 1 "sfw/core/pcg.cpp" +// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org +// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) + +uint32_t pcg32_random_r(pcg32_random_t *rng) { + uint64_t oldstate = rng->state; + // Advance internal state + rng->state = oldstate * 6364136223846793005ULL + (rng->inc | 1); + // Calculate output function (XSH RR), uses old state for max ILP + uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; + uint32_t rot = oldstate >> 59u; + return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); +} + +// Source from http://www.pcg-random.org/downloads/pcg-c-basic-0.9.zip +void pcg32_srandom_r(pcg32_random_t *rng, uint64_t initstate, uint64_t initseq) { + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + pcg32_random_r(rng); + rng->state += initstate; + pcg32_random_r(rng); +} + +// Source from https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c +// pcg32_boundedrand_r(rng, bound): +// Generate a uniformly distributed number, r, where 0 <= r < bound +uint32_t pcg32_boundedrand_r(pcg32_random_t *rng, uint32_t bound) { + // To avoid bias, we need to make the range of the RNG a multiple of + // bound, which we do by dropping output less than a threshold. + // A naive scheme to calculate the threshold would be to do + // + // uint32_t threshold = 0x100000000ull % bound; + // + // but 64-bit div/mod is slower than 32-bit div/mod (especially on + // 32-bit platforms). In essence, we do + // + // uint32_t threshold = (0x100000000ull-bound) % bound; + // + // because this version will calculate the same modulus, but the LHS + // value is less than 2^32. + uint32_t threshold = -bound % bound; + + // Uniformity guarantees that this loop will terminate. In practice, it + // should usually terminate quickly; on average (assuming all bounds are + // equally likely), 82.25% of the time, we can expect it to require just + // one iteration. In the worst case, someone passes a bound of 2^31 + 1 + // (i.e., 2147483649), which invalidates almost 50% of the range. In + // practice, bounds are typically small and only a tiny amount of the range + // is eliminated. + for (;;) { + uint32_t r = pcg32_random_r(rng); + if (r >= threshold) + return r % bound; + } +} +#line 0 + +#line 1 "sfw/core/vector2.cpp" +/*************************************************************************/ +/* vector2.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +real_t Vector2::angle() const { + return Math::atan2(y, x); +} + +real_t Vector2::length() const { + return Math::sqrt(x * x + y * y); +} + +real_t Vector2::length_squared() const { + return x * x + y * y; +} + +void Vector2::normalize() { + real_t l = x * x + y * y; + if (l != 0) { + l = Math::sqrt(l); + x /= l; + y /= l; + } +} + +Vector2 Vector2::normalized() const { + Vector2 v = *this; + v.normalize(); + return v; +} + +bool Vector2::is_normalized() const { + // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); +} + +real_t Vector2::distance_to(const Vector2 &p_vector2) const { + return Math::sqrt((x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y)); +} + +real_t Vector2::distance_squared_to(const Vector2 &p_vector2) const { + return (x - p_vector2.x) * (x - p_vector2.x) + (y - p_vector2.y) * (y - p_vector2.y); +} + +real_t Vector2::angle_to(const Vector2 &p_vector2) const { + return Math::atan2(cross(p_vector2), dot(p_vector2)); +} + +real_t Vector2::angle_to_point(const Vector2 &p_vector2) const { + return Math::atan2(y - p_vector2.y, x - p_vector2.x); +} + +real_t Vector2::dot(const Vector2 &p_other) const { + return x * p_other.x + y * p_other.y; +} + +real_t Vector2::cross(const Vector2 &p_other) const { + return x * p_other.y - y * p_other.x; +} + +Vector2 Vector2::sign() const { + return Vector2(SGN(x), SGN(y)); +} + +Vector2 Vector2::floor() const { + return Vector2(Math::floor(x), Math::floor(y)); +} + +Vector2 Vector2::ceil() const { + return Vector2(Math::ceil(x), Math::ceil(y)); +} + +Vector2 Vector2::round() const { + return Vector2(Math::round(x), Math::round(y)); +} + +Vector2 Vector2::rotated(real_t p_by) const { + Vector2 v; + v.set_rotation(angle() + p_by); + v *= length(); + return v; +} + +Vector2 Vector2::posmod(const real_t p_mod) const { + return Vector2(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod)); +} + +Vector2 Vector2::posmodv(const Vector2 &p_modv) const { + return Vector2(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y)); +} + +Vector2 Vector2::project(const Vector2 &p_to) const { + return p_to * (dot(p_to) / p_to.length_squared()); +} + +Vector2 Vector2::snapped(const Vector2 &p_by) const { + return Vector2( + Math::stepify(x, p_by.x), + Math::stepify(y, p_by.y)); +} + +Vector2 Vector2::limit_length(const real_t p_len) const { + const real_t l = length(); + Vector2 v = *this; + if (l > 0 && p_len < l) { + v /= l; + v *= p_len; + } + + return v; +} + +Vector2 Vector2::move_toward(const Vector2 &p_to, const real_t p_delta) const { + Vector2 v = *this; + Vector2 vd = p_to - v; + real_t len = vd.length(); + return len <= p_delta || len < (real_t)CMP_EPSILON ? p_to : v + vd / len * p_delta; +} + +// slide returns the component of the vector along the given plane, specified by its normal vector. +Vector2 Vector2::slide(const Vector2 &p_normal) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized."); +#endif + return *this - p_normal * this->dot(p_normal); +} + +Vector2 Vector2::bounce(const Vector2 &p_normal) const { + return -reflect(p_normal); +} + +Vector2 Vector2::reflect(const Vector2 &p_normal) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector2(), "The normal Vector2 must be normalized."); +#endif + return 2 * p_normal * this->dot(p_normal) - *this; +} + +bool Vector2::is_equal_approx(const Vector2 &p_v) const { + return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); +} + +Vector2::operator String() const { + return "(" + String::num_real(x) + ", " + String::num_real(y) + ")"; +} +#line 0 + +#line 1 "sfw/core/basis.cpp" +/*************************************************************************/ +/* basis.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +#define cofac(row1, col1, row2, col2) \ + (rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1]) + +void Basis::from_z(const Vector3 &p_z) { + if (Math::abs(p_z.z) > (real_t)Math_SQRT12) { + // choose p in y-z plane + real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2]; + real_t k = 1 / Math::sqrt(a); + rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k); + rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]); + } else { + // choose p in x-y plane + real_t a = p_z.x * p_z.x + p_z.y * p_z.y; + real_t k = 1 / Math::sqrt(a); + rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0); + rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k); + } + rows[2] = p_z; +} + +void Basis::invert() { + real_t co[3] = { + cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1) + }; + real_t det = rows[0][0] * co[0] + + rows[0][1] * co[1] + + rows[0][2] * co[2]; +#ifdef MATH_CHECKS + ERR_FAIL_COND(det == 0); +#endif + real_t s = 1 / det; + + set(co[0] * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, + co[1] * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, + co[2] * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); +} + +void Basis::orthonormalize() { + // Gram-Schmidt Process + + Vector3 x = get_column(0); + Vector3 y = get_column(1); + Vector3 z = get_column(2); + + x.normalize(); + y = (y - x * (x.dot(y))); + y.normalize(); + z = (z - x * (x.dot(z)) - y * (y.dot(z))); + z.normalize(); + + set_column(0, x); + set_column(1, y); + set_column(2, z); +} + +Basis Basis::orthonormalized() const { + Basis c = *this; + c.orthonormalize(); + return c; +} + +bool Basis::is_orthogonal() const { + Basis identity; + Basis m = (*this) * transposed(); + + return m.is_equal_approx(identity); +} + +void Basis::orthogonalize() { + Vector3 scl = get_scale(); + orthonormalize(); + scale_local(scl); +} + +Basis Basis::orthogonalized() const { + Basis c = *this; + c.orthogonalize(); + return c; +} + +bool Basis::is_diagonal() const { + return ( + Math::is_zero_approx(rows[0][1]) && Math::is_zero_approx(rows[0][2]) && + Math::is_zero_approx(rows[1][0]) && Math::is_zero_approx(rows[1][2]) && + Math::is_zero_approx(rows[2][0]) && Math::is_zero_approx(rows[2][1])); +} + +bool Basis::is_rotation() const { + return Math::is_equal_approx(determinant(), 1, (real_t)UNIT_EPSILON) && is_orthogonal(); +} + +bool Basis::is_symmetric() const { + if (!Math::is_equal_approx_ratio(rows[0][1], rows[1][0], (real_t)UNIT_EPSILON)) { + return false; + } + if (!Math::is_equal_approx_ratio(rows[0][2], rows[2][0], (real_t)UNIT_EPSILON)) { + return false; + } + if (!Math::is_equal_approx_ratio(rows[1][2], rows[2][1], (real_t)UNIT_EPSILON)) { + return false; + } + + return true; +} + +Basis Basis::diagonalize() { +//NOTE: only implemented for symmetric matrices +//with the Jacobi iterative method method +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(!is_symmetric(), Basis()); +#endif + const int ite_max = 1024; + + real_t off_matrix_norm_2 = rows[0][1] * rows[0][1] + rows[0][2] * rows[0][2] + rows[1][2] * rows[1][2]; + + int ite = 0; + Basis acc_rot; + while (off_matrix_norm_2 > (real_t)CMP_EPSILON2 && ite++ < ite_max) { + real_t el01_2 = rows[0][1] * rows[0][1]; + real_t el02_2 = rows[0][2] * rows[0][2]; + real_t el12_2 = rows[1][2] * rows[1][2]; + // Find the pivot element + int i, j; + if (el01_2 > el02_2) { + if (el12_2 > el01_2) { + i = 1; + j = 2; + } else { + i = 0; + j = 1; + } + } else { + if (el12_2 > el02_2) { + i = 1; + j = 2; + } else { + i = 0; + j = 2; + } + } + + // Compute the rotation angle + real_t angle; + if (Math::is_equal_approx(rows[j][j], rows[i][i])) { + angle = Math_PI / 4; + } else { + angle = 0.5f * Math::atan(2 * rows[i][j] / (rows[j][j] - rows[i][i])); + } + + // Compute the rotation matrix + Basis rot; + rot.rows[i][i] = rot.rows[j][j] = Math::cos(angle); + rot.rows[i][j] = -(rot.rows[j][i] = Math::sin(angle)); + + // Update the off matrix norm + off_matrix_norm_2 -= rows[i][j] * rows[i][j]; + + // Apply the rotation + *this = rot * *this * rot.transposed(); + acc_rot = rot * acc_rot; + } + + return acc_rot; +} + +Basis Basis::inverse() const { + Basis inv = *this; + inv.invert(); + return inv; +} + +void Basis::transpose() { + SWAP(rows[0][1], rows[1][0]); + SWAP(rows[0][2], rows[2][0]); + SWAP(rows[1][2], rows[2][1]); +} + +Basis Basis::transposed() const { + Basis tr = *this; + tr.transpose(); + return tr; +} + +Basis Basis::from_scale(const Vector3 &p_scale) { + return Basis(p_scale.x, 0, 0, 0, p_scale.y, 0, 0, 0, p_scale.z); +} + +// Multiplies the matrix from left by the scaling matrix: M -> S.M +// See the comment for Basis::rotated for further explanation. +void Basis::scale(const Vector3 &p_scale) { + rows[0][0] *= p_scale.x; + rows[0][1] *= p_scale.x; + rows[0][2] *= p_scale.x; + rows[1][0] *= p_scale.y; + rows[1][1] *= p_scale.y; + rows[1][2] *= p_scale.y; + rows[2][0] *= p_scale.z; + rows[2][1] *= p_scale.z; + rows[2][2] *= p_scale.z; +} + +Basis Basis::scaled(const Vector3 &p_scale) const { + Basis m = *this; + m.scale(p_scale); + return m; +} + +void Basis::scale_local(const Vector3 &p_scale) { + // performs a scaling in object-local coordinate system: + // M -> (M.S.Minv).M = M.S. + *this = scaled_local(p_scale); +} + +Basis Basis::scaled_local(const Vector3 &p_scale) const { + Basis b; + b.set_diagonal(p_scale); + + return (*this) * b; +} + +void Basis::scale_orthogonal(const Vector3 &p_scale) { + *this = scaled_orthogonal(p_scale); +} + +Basis Basis::scaled_orthogonal(const Vector3 &p_scale) const { + Basis m = *this; + Vector3 s = Vector3(-1, -1, -1) + p_scale; + Vector3 dots; + Basis b; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + dots[j] += s[i] * Math::abs(m.get_column(i).normalized().dot(b.get_column(j))); + } + } + m.scale_local(Vector3(1, 1, 1) + dots); + return m; +} + +real_t Basis::get_uniform_scale() const { + return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; +} + +void Basis::make_scale_uniform() { + float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f; + for (int i = 0; i < 3; i++) { + rows[i].normalize(); + rows[i] *= l; + } +} + +Vector3 Basis::get_scale_abs() const { + return Vector3( + Vector3(rows[0][0], rows[1][0], rows[2][0]).length(), + Vector3(rows[0][1], rows[1][1], rows[2][1]).length(), + Vector3(rows[0][2], rows[1][2], rows[2][2]).length()); +} + +Vector3 Basis::get_scale_local() const { + real_t det_sign = SGN(determinant()); + return det_sign * Vector3(rows[0].length(), rows[1].length(), rows[2].length()); +} + +// get_scale works with get_rotation, use get_scale_abs if you need to enforce positive signature. +Vector3 Basis::get_scale() const { + // FIXME: We are assuming M = R.S (R is rotation and S is scaling), and use polar decomposition to extract R and S. + // A polar decomposition is M = O.P, where O is an orthogonal matrix (meaning rotation and reflection) and + // P is a positive semi-definite matrix (meaning it contains absolute values of scaling along its diagonal). + // + // Despite being different from what we want to achieve, we can nevertheless make use of polar decomposition + // here as follows. We can split O into a rotation and a reflection as O = R.Q, and obtain M = R.S where + // we defined S = Q.P. Now, R is a proper rotation matrix and S is a (signed) scaling matrix, + // which can involve negative scalings. However, there is a catch: unlike the polar decomposition of M = O.P, + // the decomposition of O into a rotation and reflection matrix as O = R.Q is not unique. + // Therefore, we are going to do this decomposition by sticking to a particular convention. + // This may lead to confusion for some users though. + // + // The convention we use here is to absorb the sign flip into the scaling matrix. + // The same convention is also used in other similar functions such as get_rotation_axis_angle, get_rotation, ... + // + // A proper way to get rid of this issue would be to store the scaling values (or at least their signs) + // as a part of Basis. However, if we go that path, we need to disable direct (write) access to the + // matrix rows. + // + // The rotation part of this decomposition is returned by get_rotation* functions. + real_t det_sign = SGN(determinant()); + return det_sign * get_scale_abs(); +} + +// Decomposes a Basis into a rotation-reflection matrix (an element of the group O(3)) and a positive scaling matrix as B = O.S. +// Returns the rotation-reflection matrix via reference argument, and scaling information is returned as a Vector3. +// This (internal) function is too specific and named too ugly to expose to users, and probably there's no need to do so. +Vector3 Basis::rotref_posscale_decomposition(Basis &rotref) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(determinant() == 0, Vector3()); + + Basis m = transposed() * (*this); + ERR_FAIL_COND_V(!m.is_diagonal(), Vector3()); +#endif + Vector3 scale = get_scale(); + Basis inv_scale = Basis().scaled(scale.inverse()); // this will also absorb the sign of scale + rotref = (*this) * inv_scale; + +#ifdef MATH_CHECKS + ERR_FAIL_COND_V(!rotref.is_orthogonal(), Vector3()); +#endif + return scale.abs(); +} + +// Multiplies the matrix from left by the rotation matrix: M -> R.M +// Note that this does *not* rotate the matrix itself. +// +// The main use of Basis is as Transform.basis, which is used a the transformation matrix +// of 3D object. Rotate here refers to rotation of the object (which is R * (*this)), +// not the matrix itself (which is R * (*this) * R.transposed()). +Basis Basis::rotated(const Vector3 &p_axis, real_t p_phi) const { + return Basis(p_axis, p_phi) * (*this); +} + +void Basis::rotate(const Vector3 &p_axis, real_t p_phi) { + *this = rotated(p_axis, p_phi); +} + +void Basis::rotate_local(const Vector3 &p_axis, real_t p_phi) { + // performs a rotation in object-local coordinate system: + // M -> (M.R.Minv).M = M.R. + *this = rotated_local(p_axis, p_phi); +} +Basis Basis::rotated_local(const Vector3 &p_axis, real_t p_phi) const { + return (*this) * Basis(p_axis, p_phi); +} + +Basis Basis::rotated(const Vector3 &p_euler) const { + return Basis(p_euler) * (*this); +} + +void Basis::rotate(const Vector3 &p_euler) { + *this = rotated(p_euler); +} + +Basis Basis::rotated(const Quaternion &p_quat) const { + return Basis(p_quat) * (*this); +} + +void Basis::rotate(const Quaternion &p_quat) { + *this = rotated(p_quat); +} + +Vector3 Basis::get_rotation_euler() const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = orthonormalized(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + return m.get_euler(); +} + +Quaternion Basis::get_rotation_quaternion() const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = orthonormalized(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + return m.get_quaternion(); +} + +void Basis::rotate_to_align(const Vector3 &p_start_direction, const Vector3 &p_end_direction) { + // Takes two vectors and rotates the basis from the first vector to the second vector. + // Adopted from: https://gist.github.com/kevinmoran/b45980723e53edeb8a5a43c49f134724 + const Vector3 axis = p_start_direction.cross(p_end_direction).normalized(); + if (axis.length_squared() != 0) { + real_t dot = p_start_direction.dot(p_end_direction); + dot = CLAMP(dot, -1.0, 1.0); + const real_t angle_rads = Math::acos(dot); + *this = Basis(axis, angle_rads) * (*this); + } +} + +void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = orthonormalized(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + m.get_axis_angle(p_axis, p_angle); +} + +void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const { + // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, + // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). + // See the comment in get_scale() for further information. + Basis m = transposed(); + m.orthonormalize(); + real_t det = m.determinant(); + if (det < 0) { + // Ensure that the determinant is 1, such that result is a proper rotation matrix which can be represented by Euler angles. + m.scale(Vector3(-1, -1, -1)); + } + + m.get_axis_angle(p_axis, p_angle); + p_angle = -p_angle; +} + +// get_euler_xyz returns a vector containing the Euler angles in the format +// (a1,a2,a3), where a3 is the angle of the first rotation, and a1 is the last +// (following the convention they are commonly defined in the literature). +// +// The current implementation uses XYZ convention (Z is the first rotation), +// so euler.z is the angle of the (first) rotation around Z axis and so on, +// +// And thus, assuming the matrix is a rotation matrix, this function returns +// the angles in the decomposition R = X(a1).Y(a2).Z(a3) where Z(a) rotates +// around the z-axis by a and so on. +Vector3 Basis::get_euler_xyz() const { + // Euler angles in XYZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz -cy*sz sy + // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx + // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy + + Vector3 euler; + real_t sy = rows[0][2]; + if (sy < (1 - (real_t)CMP_EPSILON)) { + if (sy > -(1 - (real_t)CMP_EPSILON)) { + // is this a pure Y rotation? + if (rows[1][0] == 0 && rows[0][1] == 0 && rows[1][2] == 0 && rows[2][1] == 0 && rows[1][1] == 1) { + // return the simplest form (human friendlier in editor and scripts) + euler.x = 0; + euler.y = atan2(rows[0][2], rows[0][0]); + euler.z = 0; + } else { + euler.x = Math::atan2(-rows[1][2], rows[2][2]); + euler.y = Math::asin(sy); + euler.z = Math::atan2(-rows[0][1], rows[0][0]); + } + } else { + euler.x = Math::atan2(rows[2][1], rows[1][1]); + euler.y = -Math_PI / 2.0; + euler.z = 0.0; + } + } else { + euler.x = Math::atan2(rows[2][1], rows[1][1]); + euler.y = Math_PI / 2.0; + euler.z = 0.0; + } + return euler; +} + +// set_euler_xyz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// The current implementation uses XYZ convention (Z is the first rotation). +void Basis::set_euler_xyz(const Vector3 &p_euler) { + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1, 0, 0, 0, c, -s, 0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0, s, 0, 1, 0, -s, 0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); + + //optimizer will optimize away all this anyway + *this = xmat * (ymat * zmat); +} + +Vector3 Basis::get_euler_xzy() const { + // Euler angles in XZY convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy -sz cz*sy + // sx*sy+cx*cy*sz cx*cz cx*sz*sy-cy*sx + // cy*sx*sz cz*sx cx*cy+sx*sz*sy + + Vector3 euler; + real_t sz = rows[0][1]; + if (sz < (1 - (real_t)CMP_EPSILON)) { + if (sz > -(1 - (real_t)CMP_EPSILON)) { + euler.x = Math::atan2(rows[2][1], rows[1][1]); + euler.y = Math::atan2(rows[0][2], rows[0][0]); + euler.z = Math::asin(-sz); + } else { + // It's -1 + euler.x = -Math::atan2(rows[1][2], rows[2][2]); + euler.y = 0.0; + euler.z = Math_PI / 2.0; + } + } else { + // It's 1 + euler.x = -Math::atan2(rows[1][2], rows[2][2]); + euler.y = 0.0; + euler.z = -Math_PI / 2.0; + } + return euler; +} + +void Basis::set_euler_xzy(const Vector3 &p_euler) { + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1, 0, 0, 0, c, -s, 0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0, s, 0, 1, 0, -s, 0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); + + *this = xmat * zmat * ymat; +} + +Vector3 Basis::get_euler_yzx() const { + // Euler angles in YZX convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz sy*sx-cy*cx*sz cx*sy+cy*sz*sx + // sz cz*cx -cz*sx + // -cz*sy cy*sx+cx*sy*sz cy*cx-sy*sz*sx + + Vector3 euler; + real_t sz = rows[1][0]; + if (sz < (1 - (real_t)CMP_EPSILON)) { + if (sz > -(1 - (real_t)CMP_EPSILON)) { + euler.x = Math::atan2(-rows[1][2], rows[1][1]); + euler.y = Math::atan2(-rows[2][0], rows[0][0]); + euler.z = Math::asin(sz); + } else { + // It's -1 + euler.x = Math::atan2(rows[2][1], rows[2][2]); + euler.y = 0.0; + euler.z = -Math_PI / 2.0; + } + } else { + // It's 1 + euler.x = Math::atan2(rows[2][1], rows[2][2]); + euler.y = 0.0; + euler.z = Math_PI / 2.0; + } + return euler; +} + +void Basis::set_euler_yzx(const Vector3 &p_euler) { + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1, 0, 0, 0, c, -s, 0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0, s, 0, 1, 0, -s, 0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); + + *this = ymat * zmat * xmat; +} + +// get_euler_yxz returns a vector containing the Euler angles in the YXZ convention, +// as in first-Z, then-X, last-Y. The angles for X, Y, and Z rotations are returned +// as the x, y, and z components of a Vector3 respectively. +Vector3 Basis::get_euler_yxz() const { + // Euler angles in YXZ convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cy*cz+sy*sx*sz cz*sy*sx-cy*sz cx*sy + // cx*sz cx*cz -sx + // cy*sx*sz-cz*sy cy*cz*sx+sy*sz cy*cx + + Vector3 euler; + + real_t m12 = rows[1][2]; + + if (m12 < (1 - (real_t)CMP_EPSILON)) { + if (m12 > -(1 - (real_t)CMP_EPSILON)) { + // is this a pure X rotation? + if (rows[1][0] == 0 && rows[0][1] == 0 && rows[0][2] == 0 && rows[2][0] == 0 && rows[0][0] == 1) { + // return the simplest form (human friendlier in editor and scripts) + euler.x = atan2(-m12, rows[1][1]); + euler.y = 0; + euler.z = 0; + } else { + euler.x = asin(-m12); + euler.y = atan2(rows[0][2], rows[2][2]); + euler.z = atan2(rows[1][0], rows[1][1]); + } + } else { // m12 == -1 + euler.x = Math_PI * 0.5; + euler.y = atan2(rows[0][1], rows[0][0]); + euler.z = 0; + } + } else { // m12 == 1 + euler.x = -Math_PI * 0.5; + euler.y = -atan2(rows[0][1], rows[0][0]); + euler.z = 0; + } + + return euler; +} + +// set_euler_yxz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// The current implementation uses YXZ convention (Z is the first rotation). +void Basis::set_euler_yxz(const Vector3 &p_euler) { + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1, 0, 0, 0, c, -s, 0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0, s, 0, 1, 0, -s, 0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); + + //optimizer will optimize away all this anyway + *this = ymat * xmat * zmat; +} + +Vector3 Basis::get_euler_zxy() const { + // Euler angles in ZXY convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy-sz*sx*sy -cx*sz cz*sy+cy*sz*sx + // cy*sz+cz*sx*sy cz*cx sz*sy-cz*cy*sx + // -cx*sy sx cx*cy + Vector3 euler; + real_t sx = rows[2][1]; + if (sx < (1 - (real_t)CMP_EPSILON)) { + if (sx > -(1 - (real_t)CMP_EPSILON)) { + euler.x = Math::asin(sx); + euler.y = Math::atan2(-rows[2][0], rows[2][2]); + euler.z = Math::atan2(-rows[0][1], rows[1][1]); + } else { + // It's -1 + euler.x = -Math_PI / 2.0; + euler.y = Math::atan2(rows[0][2], rows[0][0]); + euler.z = 0; + } + } else { + // It's 1 + euler.x = Math_PI / 2.0; + euler.y = Math::atan2(rows[0][2], rows[0][0]); + euler.z = 0; + } + return euler; +} + +void Basis::set_euler_zxy(const Vector3 &p_euler) { + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1, 0, 0, 0, c, -s, 0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0, s, 0, 1, 0, -s, 0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); + + *this = zmat * xmat * ymat; +} + +Vector3 Basis::get_euler_zyx() const { + // Euler angles in ZYX convention. + // See https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix + // + // rot = cz*cy cz*sy*sx-cx*sz sz*sx+cz*cx*cy + // cy*sz cz*cx+sz*sy*sx cx*sz*sy-cz*sx + // -sy cy*sx cy*cx + Vector3 euler; + real_t sy = rows[2][0]; + if (sy < (1 - (real_t)CMP_EPSILON)) { + if (sy > -(1 - (real_t)CMP_EPSILON)) { + euler.x = Math::atan2(rows[2][1], rows[2][2]); + euler.y = Math::asin(-sy); + euler.z = Math::atan2(rows[1][0], rows[0][0]); + } else { + // It's -1 + euler.x = 0; + euler.y = Math_PI / 2.0; + euler.z = -Math::atan2(rows[0][1], rows[1][1]); + } + } else { + // It's 1 + euler.x = 0; + euler.y = -Math_PI / 2.0; + euler.z = -Math::atan2(rows[0][1], rows[1][1]); + } + return euler; +} + +void Basis::set_euler_zyx(const Vector3 &p_euler) { + real_t c, s; + + c = Math::cos(p_euler.x); + s = Math::sin(p_euler.x); + Basis xmat(1, 0, 0, 0, c, -s, 0, s, c); + + c = Math::cos(p_euler.y); + s = Math::sin(p_euler.y); + Basis ymat(c, 0, s, 0, 1, 0, -s, 0, c); + + c = Math::cos(p_euler.z); + s = Math::sin(p_euler.z); + Basis zmat(c, -s, 0, s, c, 0, 0, 0, 1); + + *this = zmat * ymat * xmat; +} + +bool Basis::is_equal_approx(const Basis &p_basis) const { + return rows[0].is_equal_approx(p_basis.rows[0]) && rows[1].is_equal_approx(p_basis.rows[1]) && rows[2].is_equal_approx(p_basis.rows[2]); +} + +bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (!Math::is_equal_approx_ratio(a.rows[i][j], b.rows[i][j], p_epsilon)) { + return false; + } + } + } + + return true; +} + +bool Basis::operator==(const Basis &p_matrix) const { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (rows[i][j] != p_matrix.rows[i][j]) { + return false; + } + } + } + + return true; +} + +bool Basis::operator!=(const Basis &p_matrix) const { + return (!(*this == p_matrix)); +} + +Basis::operator String() const { + return "[X: " + get_axis(0).operator String() + + ", Y: " + get_axis(1).operator String() + + ", Z: " + get_axis(2).operator String() + "]"; +} + +Quaternion Basis::get_quaternion() const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() if the Basis contains linearly independent vectors."); +#endif + /* Allow getting a quaternion from an unnormalized transform */ + Basis m = *this; + real_t trace = m.rows[0][0] + m.rows[1][1] + m.rows[2][2]; + real_t temp[4]; + + if (trace > 0) { + real_t s = Math::sqrt(trace + 1); + temp[3] = (s * 0.5f); + s = 0.5f / s; + + temp[0] = ((m.rows[2][1] - m.rows[1][2]) * s); + temp[1] = ((m.rows[0][2] - m.rows[2][0]) * s); + temp[2] = ((m.rows[1][0] - m.rows[0][1]) * s); + } else { + int i = m.rows[0][0] < m.rows[1][1] + ? (m.rows[1][1] < m.rows[2][2] ? 2 : 1) + : (m.rows[0][0] < m.rows[2][2] ? 2 : 0); + int j = (i + 1) % 3; + int k = (i + 2) % 3; + + real_t s = Math::sqrt(m.rows[i][i] - m.rows[j][j] - m.rows[k][k] + 1); + temp[i] = s * 0.5f; + s = 0.5f / s; + + temp[3] = (m.rows[k][j] - m.rows[j][k]) * s; + temp[j] = (m.rows[j][i] + m.rows[i][j]) * s; + temp[k] = (m.rows[k][i] + m.rows[i][k]) * s; + } + + return Quaternion(temp[0], temp[1], temp[2], temp[3]); +} + +static const Basis _ortho_bases[24] = { + Basis(1, 0, 0, 0, 1, 0, 0, 0, 1), + Basis(0, -1, 0, 1, 0, 0, 0, 0, 1), + Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1), + Basis(0, 1, 0, -1, 0, 0, 0, 0, 1), + Basis(1, 0, 0, 0, 0, -1, 0, 1, 0), + Basis(0, 0, 1, 1, 0, 0, 0, 1, 0), + Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0), + Basis(0, 0, -1, -1, 0, 0, 0, 1, 0), + Basis(1, 0, 0, 0, -1, 0, 0, 0, -1), + Basis(0, 1, 0, 1, 0, 0, 0, 0, -1), + Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1), + Basis(0, -1, 0, -1, 0, 0, 0, 0, -1), + Basis(1, 0, 0, 0, 0, 1, 0, -1, 0), + Basis(0, 0, -1, 1, 0, 0, 0, -1, 0), + Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0), + Basis(0, 0, 1, -1, 0, 0, 0, -1, 0), + Basis(0, 0, 1, 0, 1, 0, -1, 0, 0), + Basis(0, -1, 0, 0, 0, 1, -1, 0, 0), + Basis(0, 0, -1, 0, -1, 0, -1, 0, 0), + Basis(0, 1, 0, 0, 0, -1, -1, 0, 0), + Basis(0, 0, 1, 0, -1, 0, 1, 0, 0), + Basis(0, 1, 0, 0, 0, 1, 1, 0, 0), + Basis(0, 0, -1, 0, 1, 0, 1, 0, 0), + Basis(0, -1, 0, 0, 0, -1, 1, 0, 0) +}; + +int Basis::get_orthogonal_index() const { + //could be sped up if i come up with a way + Basis orth = *this; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + real_t v = orth[i][j]; + if (v > 0.5f) { + v = 1; + } else if (v < -0.5f) { + v = -1; + } else { + v = 0; + } + + orth[i][j] = v; + } + } + + for (int i = 0; i < 24; i++) { + if (_ortho_bases[i] == orth) { + return i; + } + } + + return 0; +} + +void Basis::set_orthogonal_index(int p_index) { + //there only exist 24 orthogonal bases in r3 + ERR_FAIL_INDEX(p_index, 24); + + *this = _ortho_bases[p_index]; +} + +void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { + /* checking this is a bad idea, because obtaining from scaled transform is a valid use case +#ifdef MATH_CHECKS + ERR_FAIL_COND(!is_rotation()); +#endif + */ + + // https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + real_t x, y, z; // Variables for result. + if (Math::is_zero_approx(rows[0][1] - rows[1][0]) && Math::is_zero_approx(rows[0][2] - rows[2][0]) && Math::is_zero_approx(rows[1][2] - rows[2][1])) { + // Singularity found. + // First check for identity matrix which must have +1 for all terms in leading diagonal and zero in other terms. + if (is_diagonal() && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < 3 * CMP_EPSILON)) { + // This singularity is identity matrix so angle = 0. + + r_axis = Vector3(0, 1, 0); + r_angle = 0; + return; + } + + // Otherwise this singularity is angle = 180 + real_t xx = (rows[0][0] + 1) / 2; + real_t yy = (rows[1][1] + 1) / 2; + real_t zz = (rows[2][2] + 1) / 2; + real_t xy = (rows[0][1] + rows[1][0]) / 4; + real_t xz = (rows[0][2] + rows[2][0]) / 4; + real_t yz = (rows[1][2] + rows[2][1]) / 4; + + if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term. + if (xx < CMP_EPSILON) { + x = 0; + y = Math_SQRT12; + z = Math_SQRT12; + } else { + x = Math::sqrt(xx); + y = xy / x; + z = xz / x; + } + } else if (yy > zz) { // rows[1][1] is the largest diagonal term. + if (yy < CMP_EPSILON) { + x = Math_SQRT12; + y = 0; + z = Math_SQRT12; + } else { + y = Math::sqrt(yy); + x = xy / y; + z = yz / y; + } + } else { // rows[2][2] is the largest diagonal term so base result on this. + if (zz < CMP_EPSILON) { + x = Math_SQRT12; + y = Math_SQRT12; + z = 0; + } else { + z = Math::sqrt(zz); + x = xz / z; + y = yz / z; + } + } + r_axis = Vector3(x, y, z); + r_angle = Math_PI; + return; + } + + // As we have reached here there are no singularities so we can handle normally + real_t s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise. + + if (Math::abs(s) < CMP_EPSILON) { + // Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above. + s = 1; + } + + x = (rows[2][1] - rows[1][2]) / s; + y = (rows[0][2] - rows[2][0]) / s; + z = (rows[1][0] - rows[0][1]) / s; + + r_axis = Vector3(x, y, z); + // acos does clamping. + r_angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2); +} + +void Basis::set_quaternion(const Quaternion &p_quat) { + real_t d = p_quat.length_squared(); + real_t s = 2 / d; + real_t xs = p_quat.x * s, ys = p_quat.y * s, zs = p_quat.z * s; + real_t wx = p_quat.w * xs, wy = p_quat.w * ys, wz = p_quat.w * zs; + real_t xx = p_quat.x * xs, xy = p_quat.x * ys, xz = p_quat.x * zs; + real_t yy = p_quat.y * ys, yz = p_quat.y * zs, zz = p_quat.z * zs; + set(1 - (yy + zz), xy - wz, xz + wy, + xy + wz, 1 - (xx + zz), yz - wx, + xz - wy, yz + wx, 1 - (xx + yy)); +} + +void Basis::set_axis_angle(const Vector3 &p_axis, real_t p_phi) { +// Rotation matrix from axis and angle, see https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_angle +#ifdef MATH_CHECKS + ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); +#endif + Vector3 axis_sq(p_axis.x * p_axis.x, p_axis.y * p_axis.y, p_axis.z * p_axis.z); + real_t cosine = Math::cos(p_phi); + rows[0][0] = axis_sq.x + cosine * (1 - axis_sq.x); + rows[1][1] = axis_sq.y + cosine * (1 - axis_sq.y); + rows[2][2] = axis_sq.z + cosine * (1 - axis_sq.z); + + real_t sine = Math::sin(p_phi); + real_t t = 1 - cosine; + + real_t xyzt = p_axis.x * p_axis.y * t; + real_t zyxs = p_axis.z * sine; + rows[0][1] = xyzt - zyxs; + rows[1][0] = xyzt + zyxs; + + xyzt = p_axis.x * p_axis.z * t; + zyxs = p_axis.y * sine; + rows[0][2] = xyzt + zyxs; + rows[2][0] = xyzt - zyxs; + + xyzt = p_axis.y * p_axis.z * t; + zyxs = p_axis.x * sine; + rows[1][2] = xyzt - zyxs; + rows[2][1] = xyzt + zyxs; +} + +void Basis::set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_axis, p_phi); +} + +void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_euler); +} + +void Basis::set_quaternion_scale(const Quaternion &p_quat, const Vector3 &p_scale) { + set_diagonal(p_scale); + rotate(p_quat); +} + +void Basis::set_diagonal(const Vector3 &p_diag) { + rows[0][0] = p_diag.x; + rows[0][1] = 0; + rows[0][2] = 0; + + rows[1][0] = 0; + rows[1][1] = p_diag.y; + rows[1][2] = 0; + + rows[2][0] = 0; + rows[2][1] = 0; + rows[2][2] = p_diag.z; +} + +Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { + //consider scale + Quaternion from(*this); + Quaternion to(p_to); + + Basis b(from.slerp(to, p_weight)); + b.rows[0] *= Math::lerp(rows[0].length(), p_to.rows[0].length(), p_weight); + b.rows[1] *= Math::lerp(rows[1].length(), p_to.rows[1].length(), p_weight); + b.rows[2] *= Math::lerp(rows[2].length(), p_to.rows[2].length(), p_weight); + + return b; +} + +void Basis::rotate_sh(real_t *p_values) { + // code by John Hable + // http://filmicworlds.com/blog/simple-and-fast-spherical-harmonic-rotation/ + // this code is Public Domain + + const static real_t s_c3 = 0.94617469575; // (3*sqrt(5))/(4*sqrt(pi)) + const static real_t s_c4 = -0.31539156525; // (-sqrt(5))/(4*sqrt(pi)) + const static real_t s_c5 = 0.54627421529; // (sqrt(15))/(4*sqrt(pi)) + + const static real_t s_c_scale = 1.0 / 0.91529123286551084; + const static real_t s_c_scale_inv = 0.91529123286551084; + + const static real_t s_rc2 = 1.5853309190550713 * s_c_scale; + const static real_t s_c4_div_c3 = s_c4 / s_c3; + const static real_t s_c4_div_c3_x2 = (s_c4 / s_c3) * 2.0; + + const static real_t s_scale_dst2 = s_c3 * s_c_scale_inv; + const static real_t s_scale_dst4 = s_c5 * s_c_scale_inv; + + const real_t src[9] = { p_values[0], p_values[1], p_values[2], p_values[3], p_values[4], p_values[5], p_values[6], p_values[7], p_values[8] }; + + real_t m00 = rows[0][0]; + real_t m01 = rows[0][1]; + real_t m02 = rows[0][2]; + real_t m10 = rows[1][0]; + real_t m11 = rows[1][1]; + real_t m12 = rows[1][2]; + real_t m20 = rows[2][0]; + real_t m21 = rows[2][1]; + real_t m22 = rows[2][2]; + + p_values[0] = src[0]; + p_values[1] = m11 * src[1] - m12 * src[2] + m10 * src[3]; + p_values[2] = -m21 * src[1] + m22 * src[2] - m20 * src[3]; + p_values[3] = m01 * src[1] - m02 * src[2] + m00 * src[3]; + + real_t sh0 = src[7] + src[8] + src[8] - src[5]; + real_t sh1 = src[4] + s_rc2 * src[6] + src[7] + src[8]; + real_t sh2 = src[4]; + real_t sh3 = -src[7]; + real_t sh4 = -src[5]; + + // Rotations. R0 and R1 just use the raw matrix columns + real_t r2x = m00 + m01; + real_t r2y = m10 + m11; + real_t r2z = m20 + m21; + + real_t r3x = m00 + m02; + real_t r3y = m10 + m12; + real_t r3z = m20 + m22; + + real_t r4x = m01 + m02; + real_t r4y = m11 + m12; + real_t r4z = m21 + m22; + + // dense matrix multiplication one column at a time + + // column 0 + real_t sh0_x = sh0 * m00; + real_t sh0_y = sh0 * m10; + real_t d0 = sh0_x * m10; + real_t d1 = sh0_y * m20; + real_t d2 = sh0 * (m20 * m20 + s_c4_div_c3); + real_t d3 = sh0_x * m20; + real_t d4 = sh0_x * m00 - sh0_y * m10; + + // column 1 + real_t sh1_x = sh1 * m02; + real_t sh1_y = sh1 * m12; + d0 += sh1_x * m12; + d1 += sh1_y * m22; + d2 += sh1 * (m22 * m22 + s_c4_div_c3); + d3 += sh1_x * m22; + d4 += sh1_x * m02 - sh1_y * m12; + + // column 2 + real_t sh2_x = sh2 * r2x; + real_t sh2_y = sh2 * r2y; + d0 += sh2_x * r2y; + d1 += sh2_y * r2z; + d2 += sh2 * (r2z * r2z + s_c4_div_c3_x2); + d3 += sh2_x * r2z; + d4 += sh2_x * r2x - sh2_y * r2y; + + // column 3 + real_t sh3_x = sh3 * r3x; + real_t sh3_y = sh3 * r3y; + d0 += sh3_x * r3y; + d1 += sh3_y * r3z; + d2 += sh3 * (r3z * r3z + s_c4_div_c3_x2); + d3 += sh3_x * r3z; + d4 += sh3_x * r3x - sh3_y * r3y; + + // column 4 + real_t sh4_x = sh4 * r4x; + real_t sh4_y = sh4 * r4y; + d0 += sh4_x * r4y; + d1 += sh4_y * r4z; + d2 += sh4 * (r4z * r4z + s_c4_div_c3_x2); + d3 += sh4_x * r4z; + d4 += sh4_x * r4x - sh4_y * r4y; + + // extra multipliers + p_values[4] = d0; + p_values[5] = -d1; + p_values[6] = d2 * s_scale_dst2; + p_values[7] = -d3; + p_values[8] = d4 * s_scale_dst4; +} + +Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(p_target.is_equal_approx(Vector3()), Basis(), "The target vector can't be zero."); + ERR_FAIL_COND_V_MSG(p_up.is_equal_approx(Vector3()), Basis(), "The up vector can't be zero."); +#endif + Vector3 v_z = -p_target.normalized(); + Vector3 v_x = p_up.cross(v_z); +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(v_x.is_equal_approx(Vector3()), Basis(), "The target vector and up vector can't be parallel to each other."); +#endif + v_x.normalize(); + Vector3 v_y = v_z.cross(v_x); + + Basis basis; + basis.set_columns(v_x, v_y, v_z); + return basis; +} + +#undef cofac +#line 0 + +#line 1 "sfw/core/face3.cpp" +/*************************************************************************/ +/* face3.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +int Face3::split_by_plane(const Plane &p_plane, Face3 p_res[3], bool p_is_point_over[3]) const { + ERR_FAIL_COND_V(is_degenerate(), 0); + + Vector3 above[4]; + int above_count = 0; + + Vector3 below[4]; + int below_count = 0; + + for (int i = 0; i < 3; i++) { + if (p_plane.has_point(vertex[i], (real_t)CMP_EPSILON)) { // point is in plane + + ERR_FAIL_COND_V(above_count >= 4, 0); + above[above_count++] = vertex[i]; + ERR_FAIL_COND_V(below_count >= 4, 0); + below[below_count++] = vertex[i]; + + } else { + if (p_plane.is_point_over(vertex[i])) { + //Point is over + ERR_FAIL_COND_V(above_count >= 4, 0); + above[above_count++] = vertex[i]; + + } else { + //Point is under + ERR_FAIL_COND_V(below_count >= 4, 0); + below[below_count++] = vertex[i]; + } + + /* Check for Intersection between this and the next vertex*/ + + Vector3 inters; + if (!p_plane.intersects_segment(vertex[i], vertex[(i + 1) % 3], &inters)) { + continue; + } + + /* Intersection goes to both */ + ERR_FAIL_COND_V(above_count >= 4, 0); + above[above_count++] = inters; + ERR_FAIL_COND_V(below_count >= 4, 0); + below[below_count++] = inters; + } + } + + int polygons_created = 0; + + ERR_FAIL_COND_V(above_count >= 4 && below_count >= 4, 0); //bug in the algo + + if (above_count >= 3) { + p_res[polygons_created] = Face3(above[0], above[1], above[2]); + p_is_point_over[polygons_created] = true; + polygons_created++; + + if (above_count == 4) { + p_res[polygons_created] = Face3(above[2], above[3], above[0]); + p_is_point_over[polygons_created] = true; + polygons_created++; + } + } + + if (below_count >= 3) { + p_res[polygons_created] = Face3(below[0], below[1], below[2]); + p_is_point_over[polygons_created] = false; + polygons_created++; + + if (below_count == 4) { + p_res[polygons_created] = Face3(below[2], below[3], below[0]); + p_is_point_over[polygons_created] = false; + polygons_created++; + } + } + + return polygons_created; +} + +bool Face3::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const { + //return Geometry::ray_intersects_triangle(p_from, p_dir, vertex[0], vertex[1], vertex[2], p_intersection); + return false; +} + +bool Face3::intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const { + //return Geometry::segment_intersects_triangle(p_from, p_dir, vertex[0], vertex[1], vertex[2], p_intersection); + return false; +} + +bool Face3::is_degenerate() const { + Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]); + return (normal.length_squared() < (real_t)CMP_EPSILON2); +} + +Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const { + int over = 0, under = 0; + + Plane plane = get_plane(p_clock_dir); + + for (int i = 0; i < 3; i++) { + const Vector3 &v = p_face.vertex[i]; + + if (plane.has_point(v)) { //coplanar, don't bother + continue; + } + + if (plane.is_point_over(v)) { + over++; + } else { + under++; + } + } + + if (over > 0 && under == 0) { + return SIDE_OVER; + } else if (under > 0 && over == 0) { + return SIDE_UNDER; + } else if (under == 0 && over == 0) { + return SIDE_COPLANAR; + } else { + return SIDE_SPANNING; + } +} + +Vector3 Face3::get_random_point_inside() const { + real_t a = Math::random(0, 1); + real_t b = Math::random(0, 1); + if (a > b) { + SWAP(a, b); + } + + return vertex[0] * a + vertex[1] * (b - a) + vertex[2] * (1.0 - b); +} + +Plane Face3::get_plane(ClockDirection p_dir) const { + return Plane(vertex[0], vertex[1], vertex[2], p_dir); +} + +Vector3 Face3::get_median_point() const { + return (vertex[0] + vertex[1] + vertex[2]) / 3.0; +} + +real_t Face3::get_area() const { + return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length() * 0.5; +} + +ClockDirection Face3::get_clock_dir() const { + Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]); + //printf("normal is %g,%g,%g x %g,%g,%g- wtfu is %g\n",tofloat(normal.x),tofloat(normal.y),tofloat(normal.z),tofloat(vertex[0].x),tofloat(vertex[0].y),tofloat(vertex[0].z),tofloat( normal.dot( vertex[0] ) ) ); + return (normal.dot(vertex[0]) >= 0) ? CLOCKWISE : COUNTERCLOCKWISE; +} + +bool Face3::intersects_aabb(const AABB &p_aabb) const { + /** TEST PLANE **/ + if (!p_aabb.intersects_plane(get_plane())) { + return false; + } + +#define TEST_AXIS(m_ax) \ + /** TEST FACE AXIS */ \ + { \ + real_t aabb_min = p_aabb.position.m_ax; \ + real_t aabb_max = p_aabb.position.m_ax + p_aabb.size.m_ax; \ + real_t tri_min = vertex[0].m_ax; \ + real_t tri_max = vertex[0].m_ax; \ + for (int i = 1; i < 3; i++) { \ + if (vertex[i].m_ax > tri_max) \ + tri_max = vertex[i].m_ax; \ + if (vertex[i].m_ax < tri_min) \ + tri_min = vertex[i].m_ax; \ + } \ + \ + if (tri_max < aabb_min || aabb_max < tri_min) \ + return false; \ + } + + TEST_AXIS(x); + TEST_AXIS(y); + TEST_AXIS(z); + + /** TEST ALL EDGES **/ + + Vector3 edge_norms[3] = { + vertex[0] - vertex[1], + vertex[1] - vertex[2], + vertex[2] - vertex[0], + }; + + for (int i = 0; i < 12; i++) { + Vector3 from, to; + p_aabb.get_edge(i, from, to); + Vector3 e1 = from - to; + for (int j = 0; j < 3; j++) { + Vector3 e2 = edge_norms[j]; + + Vector3 axis = vec3_cross(e1, e2); + + if (axis.length_squared() < 0.0001f) { + continue; // coplanar + } + axis.normalize(); + + real_t minA, maxA, minB, maxB; + p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); + project_range(axis, Transform(), minB, maxB); + + if (maxA < minB || maxB < minA) { + return false; + } + } + } + return true; +} + +Face3::operator String() const { + return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2]; +} + +void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { + for (int i = 0; i < 3; i++) { + Vector3 v = p_transform.xform(vertex[i]); + real_t d = p_normal.dot(v); + + if (i == 0 || d > r_max) { + r_max = d; + } + + if (i == 0 || d < r_min) { + r_min = d; + } + } +} + +void Face3::get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { +#define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.98 +#define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.05 + + if (p_max <= 0) { + return; + } + + Vector3 n = p_transform.basis.xform_inv(p_normal); + + /** TEST FACE AS SUPPORT **/ + if (get_plane().normal.dot(n) > (real_t)_FACE_IS_VALID_SUPPORT_THRESHOLD) { + *p_count = MIN(3, p_max); + + for (int i = 0; i < *p_count; i++) { + p_vertices[i] = p_transform.xform(vertex[i]); + } + + return; + } + + /** FIND SUPPORT VERTEX **/ + + int vert_support_idx = -1; + real_t support_max = 0; + + for (int i = 0; i < 3; i++) { + real_t d = n.dot(vertex[i]); + + if (i == 0 || d > support_max) { + support_max = d; + vert_support_idx = i; + } + } + + /** TEST EDGES AS SUPPORT **/ + + for (int i = 0; i < 3; i++) { + if (i != vert_support_idx && i + 1 != vert_support_idx) { + continue; + } + + // check if edge is valid as a support + real_t dot = (vertex[i] - vertex[(i + 1) % 3]).normalized().dot(n); + dot = ABS(dot); + if (dot < (real_t)_EDGE_IS_VALID_SUPPORT_THRESHOLD) { + *p_count = MIN(2, p_max); + + for (int j = 0; j < *p_count; j++) { + p_vertices[j] = p_transform.xform(vertex[(j + i) % 3]); + } + + return; + } + } + + *p_count = 1; + p_vertices[0] = p_transform.xform(vertex[vert_support_idx]); +} + +Vector3 Face3::get_closest_point_to(const Vector3 &p_point) const { + Vector3 edge0 = vertex[1] - vertex[0]; + Vector3 edge1 = vertex[2] - vertex[0]; + Vector3 v0 = vertex[0] - p_point; + + real_t a = edge0.dot(edge0); + real_t b = edge0.dot(edge1); + real_t c = edge1.dot(edge1); + real_t d = edge0.dot(v0); + real_t e = edge1.dot(v0); + + real_t det = a * c - b * b; + real_t s = b * e - c * d; + real_t t = b * d - a * e; + + if (s + t < det) { + if (s < 0.f) { + if (t < 0.f) { + if (d < 0.f) { + s = CLAMP(-d / a, 0.f, 1.f); + t = 0.f; + } else { + s = 0.f; + t = CLAMP(-e / c, 0.f, 1.f); + } + } else { + s = 0.f; + t = CLAMP(-e / c, 0.f, 1.f); + } + } else if (t < 0.f) { + s = CLAMP(-d / a, 0.f, 1.f); + t = 0.f; + } else { + real_t invDet = 1.f / det; + s *= invDet; + t *= invDet; + } + } else { + if (s < 0.f) { + real_t tmp0 = b + d; + real_t tmp1 = c + e; + if (tmp1 > tmp0) { + real_t numer = tmp1 - tmp0; + real_t denom = a - 2 * b + c; + s = CLAMP(numer / denom, 0.f, 1.f); + t = 1 - s; + } else { + t = CLAMP(-e / c, 0.f, 1.f); + s = 0.f; + } + } else if (t < 0.f) { + if (a + d > b + e) { + real_t numer = c + e - b - d; + real_t denom = a - 2 * b + c; + s = CLAMP(numer / denom, 0.f, 1.f); + t = 1 - s; + } else { + s = CLAMP(-d / a, 0.f, 1.f); + t = 0.f; + } + } else { + real_t numer = c + e - b - d; + real_t denom = a - 2 * b + c; + s = CLAMP(numer / denom, 0.f, 1.f); + t = 1.f - s; + } + } + + return vertex[0] + s * edge0 + t * edge1; +} +#line 0 + +#line 1 "sfw/core/vector4i.cpp" +/*************************************************************************/ +/* vector4i.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +void Vector4i::set_axis(const int p_axis, const int32_t p_value) { + ERR_FAIL_INDEX(p_axis, 4); + coord[p_axis] = p_value; +} + +int32_t Vector4i::get_axis(const int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 4, 0); + return operator[](p_axis); +} + +Vector4i::Axis Vector4i::min_axis() const { + uint32_t min_index = 0; + int32_t min_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) <= min_value) { + min_index = i; + min_value = operator[](i); + } + } + return Vector4i::Axis(min_index); +} + +Vector4i::Axis Vector4i::max_axis() const { + uint32_t max_index = 0; + int32_t max_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) > max_value) { + max_index = i; + max_value = operator[](i); + } + } + return Vector4i::Axis(max_index); +} + +Vector4i Vector4i::clamp(const Vector4i &p_min, const Vector4i &p_max) const { + return Vector4i( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z), + CLAMP(w, p_min.w, p_max.w)); +} + +Vector4i Vector4i::linear_interpolate(const Vector4i &p_to, const real_t p_weight) const { + return Vector4i( + x + (p_weight * (p_to.x - x)), + y + (p_weight * (p_to.y - y)), + z + (p_weight * (p_to.z - z)), + w + (p_weight * (p_to.w - w))); +} + +Vector4 Vector4i::to_vector4() const { + return Vector4(x, y, z, w); +} + +Vector4i::operator String() const { + return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ", " + itos(w) + ")"; +} + +Vector4i::operator Vector4() const { + return Vector4(x, y, z, w); +} + +/* +Vector4i::Vector4i(const Vector4 &p_vec4) { + x = p_vec4.x; + y = p_vec4.y; + z = p_vec4.z; + w = p_vec4.w; +} +*/ +#line 0 + +#line 1 "sfw/core/transform.cpp" +/*************************************************************************/ +/* transform.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +void Transform::invert() { + basis.transpose(); + origin = basis.xform(-origin); +} + +Transform Transform::inverse() const { + // FIXME: this function assumes the basis is a rotation matrix, with no scaling. + // Transform::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. + Transform ret = *this; + ret.invert(); + return ret; +} + +void Transform::affine_invert() { + basis.invert(); + origin = basis.xform(-origin); +} + +Transform Transform::affine_inverse() const { + Transform ret = *this; + ret.affine_invert(); + return ret; +} + +Transform Transform::rotated(const Vector3 &p_axis, real_t p_angle) const { + // Equivalent to left multiplication + Basis p_basis(p_axis, p_angle); + return Transform(p_basis * basis, p_basis.xform(origin)); +} + +Transform Transform::rotated_local(const Vector3 &p_axis, real_t p_angle) const { + // Equivalent to right multiplication + Basis p_basis(p_axis, p_angle); + return Transform(basis * p_basis, origin); +} + +void Transform::rotate(const Vector3 &p_axis, real_t p_phi) { + *this = rotated(p_axis, p_phi); +} + +void Transform::rotate_local(const Vector3 &p_axis, real_t p_phi) { + *this = rotated_local(p_axis, p_phi); +} + +void Transform::rotate_basis(const Vector3 &p_axis, real_t p_phi) { + basis.rotate(p_axis, p_phi); +} + +void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +#ifdef MATH_CHECKS + ERR_FAIL_COND(p_eye == p_target); + ERR_FAIL_COND(p_up.length() == 0); +#endif + // Reference: MESA source code + Vector3 v_x, v_y, v_z; + + /* Make rotation matrix */ + + /* Z vector */ + v_z = p_eye - p_target; + + v_z.normalize(); + + v_y = p_up; + + v_x = v_y.cross(v_z); +#ifdef MATH_CHECKS + ERR_FAIL_COND(v_x.length() == 0); +#endif + + /* Recompute Y = Z cross X */ + v_y = v_z.cross(v_x); + + v_x.normalize(); + v_y.normalize(); + + basis.set(v_x, v_y, v_z); + + origin = p_eye; +} + +Transform Transform::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { + Transform t = *this; + t.set_look_at(origin, p_target, p_up); + return t; +} + +void Transform::scale(const Vector3 &p_scale) { + basis.scale(p_scale); + origin *= p_scale; +} + +Transform Transform::scaled(const Vector3 &p_scale) const { + // Equivalent to left multiplication + return Transform(basis.scaled(p_scale), origin * p_scale); +} + +Transform Transform::scaled_local(const Vector3 &p_scale) const { + // Equivalent to right multiplication + return Transform(basis.scaled_local(p_scale), origin); +} + +void Transform::scale_basis(const Vector3 &p_scale) { + basis.scale(p_scale); +} + +void Transform::translate_local(real_t p_tx, real_t p_ty, real_t p_tz) { + translate_local(Vector3(p_tx, p_ty, p_tz)); +} +void Transform::translate_local(const Vector3 &p_translation) { + for (int i = 0; i < 3; i++) { + origin[i] += basis[i].dot(p_translation); + } +} + +void Transform::translate_localr(real_t p_tx, real_t p_ty, real_t p_tz) { + translate_local(Vector3(p_tx, p_ty, p_tz)); +} +void Transform::translate_localv(const Vector3 &p_translation) { + for (int i = 0; i < 3; i++) { + origin[i] += basis[i].dot(p_translation); + } +} + +Transform Transform::translated(const Vector3 &p_translation) const { + // Equivalent to left multiplication + return Transform(basis, origin + p_translation); +} + +Transform Transform::translated_local(const Vector3 &p_translation) const { + // Equivalent to right multiplication + return Transform(basis, origin + basis.xform(p_translation)); +} + +void Transform::orthonormalize() { + basis.orthonormalize(); +} + +Transform Transform::orthonormalized() const { + Transform _copy = *this; + _copy.orthonormalize(); + return _copy; +} + +void Transform::orthogonalize() { + basis.orthogonalize(); +} + +Transform Transform::orthogonalized() const { + Transform _copy = *this; + _copy.orthogonalize(); + return _copy; +} + +bool Transform::is_equal_approx(const Transform &p_transform) const { + return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); +} + +bool Transform::operator==(const Transform &p_transform) const { + return (basis == p_transform.basis && origin == p_transform.origin); +} +bool Transform::operator!=(const Transform &p_transform) const { + return (basis != p_transform.basis || origin != p_transform.origin); +} + +void Transform::operator*=(const Transform &p_transform) { + origin = xform(p_transform.origin); + basis *= p_transform.basis; +} + +Transform Transform::operator*(const Transform &p_transform) const { + Transform t = *this; + t *= p_transform; + return t; +} + +void Transform::operator*=(const real_t p_val) { + origin *= p_val; + basis *= p_val; +} + +Transform Transform::operator*(const real_t p_val) const { + Transform ret(*this); + ret *= p_val; + return ret; +} + +Transform Transform::spherical_interpolate_with(const Transform &p_transform, real_t p_c) const { + /* not sure if very "efficient" but good enough? */ + + Transform interp; + + Vector3 src_scale = basis.get_scale(); + Quaternion src_rot = basis.get_rotation_quaternion(); + Vector3 src_loc = origin; + + Vector3 dst_scale = p_transform.basis.get_scale(); + Quaternion dst_rot = p_transform.basis.get_rotation_quaternion(); + Vector3 dst_loc = p_transform.origin; + + interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.linear_interpolate(dst_scale, p_c)); + interp.origin = src_loc.linear_interpolate(dst_loc, p_c); + + return interp; +} + +Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) const { + /* not sure if very "efficient" but good enough? */ + + Vector3 src_scale = basis.get_scale(); + Quaternion src_rot = basis.get_rotation_quaternion(); + Vector3 src_loc = origin; + + Vector3 dst_scale = p_transform.basis.get_scale(); + Quaternion dst_rot = p_transform.basis.get_rotation_quaternion(); + Vector3 dst_loc = p_transform.origin; + + Transform interp; + interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.linear_interpolate(dst_scale, p_c)); + interp.origin = src_loc.linear_interpolate(dst_loc, p_c); + + return interp; +} + +Transform::operator String() const { + return "[X: " + basis.get_axis(0).operator String() + + ", Y: " + basis.get_axis(1).operator String() + + ", Z: " + basis.get_axis(2).operator String() + + ", O: " + origin.operator String() + "]"; +} + +Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) : + basis(p_basis), + origin(p_origin) { +} + +Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { + basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz); + origin = Vector3(ox, oy, oz); +} + +Transform::Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : + origin(p_origin) { + basis.set_column(0, p_x); + basis.set_column(1, p_y); + basis.set_column(2, p_z); +} +#line 0 + +#line 1 "sfw/core/color.cpp" /*************************************************************************/ /* color.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -9412,7 +13356,446 @@ Color Color::operator-() const { } #line 0 -#line 1 "sfwl/core/vector2i.cpp" +#line 1 "sfw/core/quaternion.cpp" +/*************************************************************************/ +/* quaternion.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +real_t Quaternion::angle_to(const Quaternion &p_to) const { + real_t d = dot(p_to); + + // acos does clamping. + return Math::acos(d * d * 2 - 1); +} + +// set_euler_xyz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses XYZ convention (Z is the first rotation). +void Quaternion::set_euler_xyz(const Vector3 &p_euler) { + real_t half_a1 = p_euler.x * 0.5f; + real_t half_a2 = p_euler.y * 0.5f; + real_t half_a3 = p_euler.z * 0.5f; + + // R = X(a1).Y(a2).Z(a3) convention for Euler angles. + // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-2) + // a3 is the angle of the first rotation, following the notation in this reference. + + real_t cos_a1 = Math::cos(half_a1); + real_t sin_a1 = Math::sin(half_a1); + real_t cos_a2 = Math::cos(half_a2); + real_t sin_a2 = Math::sin(half_a2); + real_t cos_a3 = Math::cos(half_a3); + real_t sin_a3 = Math::sin(half_a3); + + set(sin_a1 * cos_a2 * cos_a3 + sin_a2 * sin_a3 * cos_a1, + -sin_a1 * sin_a3 * cos_a2 + sin_a2 * cos_a1 * cos_a3, + sin_a1 * sin_a2 * cos_a3 + sin_a3 * cos_a1 * cos_a2, + -sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3); +} + +// get_euler_xyz returns a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses XYZ convention (Z is the first rotation). +Vector3 Quaternion::get_euler_xyz() const { + Basis m(*this); + return m.get_euler_xyz(); +} + +// set_euler_yxz expects a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses YXZ convention (Z is the first rotation). +void Quaternion::set_euler_yxz(const Vector3 &p_euler) { + real_t half_a1 = p_euler.y * 0.5f; + real_t half_a2 = p_euler.x * 0.5f; + real_t half_a3 = p_euler.z * 0.5f; + + // R = Y(a1).X(a2).Z(a3) convention for Euler angles. + // Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6) + // a3 is the angle of the first rotation, following the notation in this reference. + + real_t cos_a1 = Math::cos(half_a1); + real_t sin_a1 = Math::sin(half_a1); + real_t cos_a2 = Math::cos(half_a2); + real_t sin_a2 = Math::sin(half_a2); + real_t cos_a3 = Math::cos(half_a3); + real_t sin_a3 = Math::sin(half_a3); + + set(sin_a1 * cos_a2 * sin_a3 + cos_a1 * sin_a2 * cos_a3, + sin_a1 * cos_a2 * cos_a3 - cos_a1 * sin_a2 * sin_a3, + -sin_a1 * sin_a2 * cos_a3 + cos_a1 * cos_a2 * sin_a3, + sin_a1 * sin_a2 * sin_a3 + cos_a1 * cos_a2 * cos_a3); +} + +// get_euler_yxz returns a vector containing the Euler angles in the format +// (ax,ay,az), where ax is the angle of rotation around x axis, +// and similar for other axes. +// This implementation uses YXZ convention (Z is the first rotation). +Vector3 Quaternion::get_euler_yxz() const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized."); +#endif + Basis m(*this); + return m.get_euler_yxz(); +} + +void Quaternion::operator*=(const Quaternion &p_q) { + set(w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y, + w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z, + w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x, + w * p_q.w - x * p_q.x - y * p_q.y - z * p_q.z); +} + +Quaternion Quaternion::operator*(const Quaternion &p_q) const { + Quaternion r = *this; + r *= p_q; + return r; +} + +bool Quaternion::is_equal_approx(const Quaternion &p_quat) const { + return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w); +} + +real_t Quaternion::length() const { + return Math::sqrt(length_squared()); +} + +void Quaternion::normalize() { + *this /= length(); +} + +Quaternion Quaternion::normalized() const { + return *this / length(); +} + +bool Quaternion::is_normalized() const { + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon +} + +Quaternion Quaternion::inverse() const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized."); +#endif + return Quaternion(-x, -y, -z, w); +} + +Quaternion Quaternion::log() const { + Quaternion src = *this; + Vector3 src_v = src.get_axis() * src.get_angle(); + return Quaternion(src_v.x, src_v.y, src_v.z, 0); +} + +Quaternion Quaternion::exp() const { + Quaternion src = *this; + Vector3 src_v = Vector3(src.x, src.y, src.z); + float theta = src_v.length(); + if (theta < CMP_EPSILON) { + return Quaternion(0, 0, 0, 1); + } + return Quaternion(src_v.normalized(), theta); +} + +Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); +#endif + Quaternion to1; + real_t omega, cosom, sinom, scale0, scale1; + + // calc cosine + cosom = dot(p_to); + + // adjust signs (if necessary) + if (cosom < 0) { + cosom = -cosom; + to1.x = -p_to.x; + to1.y = -p_to.y; + to1.z = -p_to.z; + to1.w = -p_to.w; + } else { + to1.x = p_to.x; + to1.y = p_to.y; + to1.z = p_to.z; + to1.w = p_to.w; + } + + // calculate coefficients + + if ((1 - cosom) > (real_t)CMP_EPSILON) { + // standard case (slerp) + omega = Math::acos(cosom); + sinom = Math::sin(omega); + scale0 = Math::sin((1 - p_weight) * omega) / sinom; + scale1 = Math::sin(p_weight * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1 - p_weight; + scale1 = p_weight; + } + // calculate final values + return Quaternion( + scale0 * x + scale1 * to1.x, + scale0 * y + scale1 * to1.y, + scale0 * z + scale1 * to1.z, + scale0 * w + scale1 * to1.w); +} + +Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); +#endif + const Quaternion &from = *this; + + real_t dot = from.dot(p_to); + + if (Math::absf(dot) > 0.9999f) { + return from; + } + + real_t theta = Math::acos(dot), + sinT = 1 / Math::sin(theta), + newFactor = Math::sin(p_weight * theta) * sinT, + invFactor = Math::sin((1 - p_weight) * theta) * sinT; + + return Quaternion(invFactor * from.x + newFactor * p_to.x, + invFactor * from.y + newFactor * p_to.y, + invFactor * from.z + newFactor * p_to.z, + invFactor * from.w + newFactor * p_to.w); +} + +Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); +#endif + //the only way to do slerp :| + real_t t2 = (1 - p_weight) * p_weight * 2; + Quaternion sp = this->slerp(p_b, p_weight); + Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight); + return sp.slerpni(sq, t2); +} + +Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); +#endif + Quaternion from_q = *this; + Quaternion pre_q = p_pre_a; + Quaternion to_q = p_b; + Quaternion post_q = p_post_b; + + // Align flip phases. + from_q = Basis(from_q).get_rotation_quaternion(); + pre_q = Basis(pre_q).get_rotation_quaternion(); + to_q = Basis(to_q).get_rotation_quaternion(); + post_q = Basis(post_q).get_rotation_quaternion(); + + // Flip quaternions to shortest path if necessary. + bool flip1 = signbit(from_q.dot(pre_q)); + pre_q = flip1 ? -pre_q : pre_q; + bool flip2 = signbit(from_q.dot(to_q)); + to_q = flip2 ? -to_q : to_q; + bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q)); + post_q = flip3 ? -post_q : post_q; + + // Calc by Expmap in from_q space. + Quaternion ln_from = Quaternion(0, 0, 0, 0); + Quaternion ln_to = (from_q.inverse() * to_q).log(); + Quaternion ln_pre = (from_q.inverse() * pre_q).log(); + Quaternion ln_post = (from_q.inverse() * post_q).log(); + Quaternion ln = Quaternion(0, 0, 0, 0); + ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight); + ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight); + ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight); + Quaternion q1 = from_q * ln.exp(); + + // Calc by Expmap in to_q space. + ln_from = (to_q.inverse() * from_q).log(); + ln_to = Quaternion(0, 0, 0, 0); + ln_pre = (to_q.inverse() * pre_q).log(); + ln_post = (to_q.inverse() * post_q).log(); + ln = Quaternion(0, 0, 0, 0); + ln.x = Math::cubic_interpolate(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight); + ln.y = Math::cubic_interpolate(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight); + ln.z = Math::cubic_interpolate(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight); + Quaternion q2 = to_q * ln.exp(); + + // To cancel error made by Expmap ambiguity, do blends. + return q1.slerp(q2, p_weight); +} + +Vector3 Quaternion::get_axis() const { + if (Math::abs(w) > 1 - CMP_EPSILON) { + return Vector3(x, y, z); + } + real_t r = ((real_t)1) / Math::sqrt(1 - w * w); + return Vector3(x * r, y * r, z * r); +} + +float Quaternion::get_angle() const { + return 2 * Math::acos(w); +} + +Quaternion::operator String() const { + return "(" + String::num_real(x) + ", " + String::num_real(y) + ", " + String::num_real(z) + ", " + String::num_real(w) + ")"; +} + +void Quaternion::set_axis_angle(const Vector3 &axis, const real_t &angle) { +#ifdef MATH_CHECKS + ERR_FAIL_COND_MSG(!axis.is_normalized(), "The axis Vector3 must be normalized."); +#endif + real_t d = axis.length(); + if (d == 0) { + set(0, 0, 0, 0); + } else { + real_t sin_angle = Math::sin(angle * 0.5f); + real_t cos_angle = Math::cos(angle * 0.5f); + real_t s = sin_angle / d; + set(axis.x * s, axis.y * s, axis.z * s, + cos_angle); + } +} +#line 0 + +#line 1 "sfw/core/plane.cpp" +/*************************************************************************/ +/* plane.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +void Plane::set_normal(const Vector3 &p_normal) { + normal = p_normal; +} + +void Plane::normalize() { + real_t l = normal.length(); + if (l == 0) { + *this = Plane(0, 0, 0, 0); + return; + } + normal /= l; + d /= l; +} + +Plane Plane::normalized() const { + Plane p = *this; + p.normalize(); + return p; +} + +Vector3 Plane::get_any_point() const { + return get_normal() * d; +} + +Vector3 Plane::get_any_perpendicular_normal() const { + static const Vector3 p1 = Vector3(1, 0, 0); + static const Vector3 p2 = Vector3(0, 1, 0); + Vector3 p; + + if (ABS(normal.dot(p1)) > 0.99f) { // if too similar to p1 + p = p2; // use p2 + } else { + p = p1; // use p1 + } + + p -= normal * normal.dot(p); + p.normalize(); + + return p; +} + +/* intersections */ + +bool Plane::intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result) const { + const Plane &p_plane0 = *this; + Vector3 normal0 = p_plane0.normal; + Vector3 normal1 = p_plane1.normal; + Vector3 normal2 = p_plane2.normal; + + real_t denom = vec3_cross(normal0, normal1).dot(normal2); + + if (Math::is_zero_approx(denom)) { + return false; + } + + if (r_result) { + *r_result = ((vec3_cross(normal1, normal2) * p_plane0.d) + + (vec3_cross(normal2, normal0) * p_plane1.d) + + (vec3_cross(normal0, normal1) * p_plane2.d)) / + denom; + } + + return true; +} + +bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const { + Vector3 segment = p_dir; + real_t den = normal.dot(segment); + + //printf("den is %i\n",den); + if (Math::is_zero_approx(den)) { + return false; + } + + real_t dist = (normal.dot(p_from) - d) / den; + //printf("dist is %i\n",dist); + + if (dist > (real_t)CMP_EPSILON) { //this is a ray, before the emitting pos (p_from) doesn't exist + + return false; + } + + dist = -dist; + *p_intersection = p_from + segment * dist; + + return true; +} + +bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const { + Vector3 segment = p_begin - p_end; + real_t den = normal.dot(segment); + + //printf("den is %i\n",den); + if (Math::is_zero_approx(den)) { + return false; + } + + real_t dist = (normal.dot(p_begin) - d) / den; + //printf("dist is %i\n",dist); + + if (dist < (real_t)-CMP_EPSILON || dist > (1 + (real_t)CMP_EPSILON)) { + return false; + } + + dist = -dist; + *p_intersection = p_begin + segment * dist; + + return true; +} + +/* misc */ + +bool Plane::is_equal_approx(const Plane &p_plane) const { + return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d); +} + +bool Plane::is_equal_approx_any_side(const Plane &p_plane) const { + return (normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d)) || (normal.is_equal_approx(-p_plane.normal) && Math::is_equal_approx(d, -p_plane.d)); +} + +Plane::operator String() const { + return "[N: " + normal.operator String() + ", D: " + String::num_real(d) + "]"; +} +#line 0 + +#line 1 "sfw/core/vector2i.cpp" /*************************************************************************/ /* vector2i.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -9488,7 +13871,252 @@ Vector2i::operator String() const { } #line 0 -#line 1 "sfwl/core/rect2i.cpp" +#line 1 "sfw/core/rect2.cpp" +/*************************************************************************/ +/* rect2.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +bool Rect2::is_equal_approx(const Rect2 &p_rect) const { + return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size); +} + +bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const { + real_t min = 0, max = 1; + int axis = 0; + real_t sign = 0; + + for (int i = 0; i < 2; i++) { + real_t seg_from = p_from[i]; + real_t seg_to = p_to[i]; + real_t box_begin = position[i]; + real_t box_end = box_begin + size[i]; + real_t cmin, cmax; + real_t csign; + + if (seg_from < seg_to) { + if (seg_from > box_end || seg_to < box_begin) { + return false; + } + real_t length = seg_to - seg_from; + cmin = (seg_from < box_begin) ? ((box_begin - seg_from) / length) : 0; + cmax = (seg_to > box_end) ? ((box_end - seg_from) / length) : 1; + csign = -1.0; + + } else { + if (seg_to > box_end || seg_from < box_begin) { + return false; + } + real_t length = seg_to - seg_from; + cmin = (seg_from > box_end) ? (box_end - seg_from) / length : 0; + cmax = (seg_to < box_begin) ? (box_begin - seg_from) / length : 1; + csign = 1.0; + } + + if (cmin > min) { + min = cmin; + axis = i; + sign = csign; + } + if (cmax < max) { + max = cmax; + } + if (max < min) { + return false; + } + } + + Vector2 rel = p_to - p_from; + + if (r_normal) { + Vector2 normal; + normal[axis] = sign; + *r_normal = normal; + } + + if (r_pos) { + *r_pos = p_from + rel * min; + } + + return true; +} + +bool Rect2::intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const { + //SAT intersection between local and transformed rect2 + + Vector2 xf_points[4] = { + p_xform.xform(p_rect.position), + p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)), + p_xform.xform(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), + p_xform.xform(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), + }; + + real_t low_limit; + + //base rect2 first (faster) + + if (xf_points[0].y > position.y) { + goto next1; + } + if (xf_points[1].y > position.y) { + goto next1; + } + if (xf_points[2].y > position.y) { + goto next1; + } + if (xf_points[3].y > position.y) { + goto next1; + } + + return false; + +next1: + + low_limit = position.y + size.y; + + if (xf_points[0].y < low_limit) { + goto next2; + } + if (xf_points[1].y < low_limit) { + goto next2; + } + if (xf_points[2].y < low_limit) { + goto next2; + } + if (xf_points[3].y < low_limit) { + goto next2; + } + + return false; + +next2: + + if (xf_points[0].x > position.x) { + goto next3; + } + if (xf_points[1].x > position.x) { + goto next3; + } + if (xf_points[2].x > position.x) { + goto next3; + } + if (xf_points[3].x > position.x) { + goto next3; + } + + return false; + +next3: + + low_limit = position.x + size.x; + + if (xf_points[0].x < low_limit) { + goto next4; + } + if (xf_points[1].x < low_limit) { + goto next4; + } + if (xf_points[2].x < low_limit) { + goto next4; + } + if (xf_points[3].x < low_limit) { + goto next4; + } + + return false; + +next4: + + Vector2 xf_points2[4] = { + position, + Vector2(position.x + size.x, position.y), + Vector2(position.x, position.y + size.y), + Vector2(position.x + size.x, position.y + size.y), + }; + + real_t maxa = p_xform.columns[0].dot(xf_points2[0]); + real_t mina = maxa; + + real_t dp = p_xform.columns[0].dot(xf_points2[1]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.columns[0].dot(xf_points2[2]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.columns[0].dot(xf_points2[3]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + real_t maxb = p_xform.columns[0].dot(xf_points[0]); + real_t minb = maxb; + + dp = p_xform.columns[0].dot(xf_points[1]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.columns[0].dot(xf_points[2]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.columns[0].dot(xf_points[3]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + if (mina > maxb) { + return false; + } + if (minb > maxa) { + return false; + } + + maxa = p_xform.columns[1].dot(xf_points2[0]); + mina = maxa; + + dp = p_xform.columns[1].dot(xf_points2[1]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.columns[1].dot(xf_points2[2]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + dp = p_xform.columns[1].dot(xf_points2[3]); + maxa = MAX(dp, maxa); + mina = MIN(dp, mina); + + maxb = p_xform.columns[1].dot(xf_points[0]); + minb = maxb; + + dp = p_xform.columns[1].dot(xf_points[1]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.columns[1].dot(xf_points[2]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + dp = p_xform.columns[1].dot(xf_points[3]); + maxb = MAX(dp, maxb); + minb = MIN(dp, minb); + + if (mina > maxb) { + return false; + } + if (minb > maxa) { + return false; + } + + return true; +} + +Rect2::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} +#line 0 + +#line 1 "sfw/core/rect2i.cpp" /*************************************************************************/ /* rect2i.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -9499,64 +14127,167 @@ Rect2i::operator String() const { } #line 0 -#line 1 "sfwl/core/pcg.cpp" -// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org -// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) +#line 1 "sfw/core/vector4.cpp" +/*************************************************************************/ +/* vector4.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ -uint32_t pcg32_random_r(pcg32_random_t *rng) { - uint64_t oldstate = rng->state; - // Advance internal state - rng->state = oldstate * 6364136223846793005ULL + (rng->inc | 1); - // Calculate output function (XSH RR), uses old state for max ILP - uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; - uint32_t rot = oldstate >> 59u; - return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); +void Vector4::set_axis(const int p_axis, const real_t p_value) { + ERR_FAIL_INDEX(p_axis, 4); + components[p_axis] = p_value; } -// Source from http://www.pcg-random.org/downloads/pcg-c-basic-0.9.zip -void pcg32_srandom_r(pcg32_random_t *rng, uint64_t initstate, uint64_t initseq) { - rng->state = 0U; - rng->inc = (initseq << 1u) | 1u; - pcg32_random_r(rng); - rng->state += initstate; - pcg32_random_r(rng); +real_t Vector4::get_axis(const int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 4, 0); + return operator[](p_axis); } -// Source from https://github.com/imneme/pcg-c-basic/blob/master/pcg_basic.c -// pcg32_boundedrand_r(rng, bound): -// Generate a uniformly distributed number, r, where 0 <= r < bound -uint32_t pcg32_boundedrand_r(pcg32_random_t *rng, uint32_t bound) { - // To avoid bias, we need to make the range of the RNG a multiple of - // bound, which we do by dropping output less than a threshold. - // A naive scheme to calculate the threshold would be to do - // - // uint32_t threshold = 0x100000000ull % bound; - // - // but 64-bit div/mod is slower than 32-bit div/mod (especially on - // 32-bit platforms). In essence, we do - // - // uint32_t threshold = (0x100000000ull-bound) % bound; - // - // because this version will calculate the same modulus, but the LHS - // value is less than 2^32. - uint32_t threshold = -bound % bound; - - // Uniformity guarantees that this loop will terminate. In practice, it - // should usually terminate quickly; on average (assuming all bounds are - // equally likely), 82.25% of the time, we can expect it to require just - // one iteration. In the worst case, someone passes a bound of 2^31 + 1 - // (i.e., 2147483649), which invalidates almost 50% of the range. In - // practice, bounds are typically small and only a tiny amount of the range - // is eliminated. - for (;;) { - uint32_t r = pcg32_random_r(rng); - if (r >= threshold) - return r % bound; +Vector4::Axis Vector4::min_axis() const { + uint32_t min_index = 0; + real_t min_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) <= min_value) { + min_index = i; + min_value = operator[](i); + } } + return Vector4::Axis(min_index); +} + +Vector4::Axis Vector4::max_axis() const { + uint32_t max_index = 0; + real_t max_value = x; + for (uint32_t i = 1; i < 4; i++) { + if (operator[](i) > max_value) { + max_index = i; + max_value = operator[](i); + } + } + return Vector4::Axis(max_index); +} + +bool Vector4::is_equal_approx(const Vector4 &p_vec4) const { + return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w); +} + +real_t Vector4::length() const { + return Math::sqrt(length_squared()); +} + +void Vector4::normalize() { + *this /= length(); +} + +Vector4 Vector4::normalized() const { + return *this / length(); +} + +bool Vector4::is_normalized() const { + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon. +} + +Vector4 Vector4::limit_length(const real_t p_len) const { + const real_t l = length(); + Vector4 v = *this; + if (l > 0 && p_len < l) { + v /= l; + v *= p_len; + } + + return v; +} + +real_t Vector4::distance_to(const Vector4 &p_to) const { + return (p_to - *this).length(); +} + +Vector4 Vector4::direction_to(const Vector4 &p_to) const { + Vector4 ret(p_to.x - x, p_to.y - y, p_to.z - z, p_to.w - w); + ret.normalize(); + return ret; +} + +real_t Vector4::distance_squared_to(const Vector4 &p_to) const { + return (p_to - *this).length_squared(); +} + +Vector4 Vector4::abs() const { + return Vector4(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w)); +} + +Vector4 Vector4::sign() const { + return Vector4(SGN(x), SGN(y), SGN(z), SGN(w)); +} + +Vector4 Vector4::floor() const { + return Vector4(Math::floor(x), Math::floor(y), Math::floor(z), Math::floor(w)); +} + +Vector4 Vector4::ceil() const { + return Vector4(Math::ceil(x), Math::ceil(y), Math::ceil(z), Math::ceil(w)); +} + +Vector4 Vector4::round() const { + return Vector4(Math::round(x), Math::round(y), Math::round(z), Math::round(w)); +} + +Vector4 Vector4::linear_interpolate(const Vector4 &p_to, const real_t p_weight) const { + return Vector4( + x + (p_weight * (p_to.x - x)), + y + (p_weight * (p_to.y - y)), + z + (p_weight * (p_to.z - z)), + w + (p_weight * (p_to.w - w))); +} + +Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const { + Vector4 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); + res.w = Math::cubic_interpolate(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight); + return res; +} + +Vector4 Vector4::posmod(const real_t p_mod) const { + return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod)); +} + +Vector4 Vector4::posmodv(const Vector4 &p_modv) const { + return Vector4(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z), Math::fposmod(w, p_modv.w)); +} + +void Vector4::snap(const Vector4 &p_step) { + x = Math::stepify(x, p_step.x); + y = Math::stepify(y, p_step.y); + z = Math::stepify(z, p_step.z); + w = Math::stepify(w, p_step.w); +} + +Vector4 Vector4::snapped(const Vector4 &p_step) const { + Vector4 v = *this; + v.snap(p_step); + return v; +} + +Vector4 Vector4::inverse() const { + return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w); +} + +Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const { + return Vector4( + CLAMP(x, p_min.x, p_max.x), + CLAMP(y, p_min.y, p_max.y), + CLAMP(z, p_min.z, p_max.z), + CLAMP(w, p_min.w, p_max.w)); +} + +Vector4::operator String() const { + return "(" + String::num_real(x) + ", " + String::num_real(y) + ", " + String::num_real(z) + ", " + String::num_real(w) + ")"; } #line 0 -#line 1 "sfwl/core/file_access.cpp" +#line 1 "sfw/core/file_access.cpp" /*************************************************************************/ /* file_access.cpp */ @@ -9663,7 +14394,7 @@ Error FileAccess::_open(const String &p_path, int p_mode_flags) { if (fname != String()) { String base_file = path.get_file(); if (base_file != fname && base_file.findn(fname) == 0) { - LOG_WARN("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); + WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); } } @@ -10736,7 +15467,7 @@ FileAccess::FileAccess() { */ #line 0 -#line 1 "sfwl/core/dir_access.cpp" +#line 1 "sfw/core/dir_access.cpp" /*************************************************************************/ /* dir_access.cpp */ @@ -11919,7 +16650,7 @@ bool DirAccess::is_special(const String &p_path) { } #line 0 -#line 1 "sfwl/core/inet_address.cpp" +#line 1 "sfw/core/inet_address.cpp" //Based on: // Copyright 2010, Shuo Chen. All rights reserved. @@ -12247,7 +16978,7 @@ InetAddress::~InetAddress() { } #line 0 -#line 1 "sfwl/core/socket.cpp" +#line 1 "sfw/core/socket.cpp" //Based on: @@ -12598,7 +17329,7 @@ Socket::~Socket() { } #line 0 -#line 1 "sfwl/core/sub_process.cpp" +#line 1 "sfw/core/sub_process.cpp" /*************************************************************************/ /* sub_process.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -13358,7 +18089,7 @@ void SubProcess::_setup_pipe_mutex() { } #line 0 -#line 1 "sfwl/core/sfw_core.cpp" +#line 1 "sfw/core/sfw_core.cpp" void SFWCore::setup() { if (_initialized) { @@ -13387,7 +18118,7 @@ bool SFWCore::_initialized = false; //=================== OBJECT SECTION =================== -#line 1 "sfwl/object/resource.cpp" +#line 1 "sfw/object/resource.cpp" void Resource::emit_changed() { changed.emit(this); @@ -13408,7 +18139,7 @@ Resource::~Resource() { } #line 0 -#line 1 "sfwl/object/reference.cpp" +#line 1 "sfw/object/reference.cpp" /*************************************************************************/ /* reference.cpp */ @@ -13469,7 +18200,7 @@ WeakRef::WeakRef() : \ */ \ #line 0 -#line 1 "sfwl/object/object.cpp" +#line 1 "sfw/object/object.cpp" void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid) { if (p_name == CoreStringNames::get_singleton()->_meta) { @@ -13690,7 +18421,7 @@ void ObjectDB::cleanup() { } #line 0 -#line 1 "sfwl/object/ref_ptr.cpp" +#line 1 "sfw/object/ref_ptr.cpp" /*************************************************************************/ /* ref_ptr.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -13747,7 +18478,7 @@ RefPtr::~RefPtr() { } #line 0 -#line 1 "sfwl/object/core_string_names.cpp" +#line 1 "sfw/object/core_string_names.cpp" /*************************************************************************/ /* core_string_names.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -13797,7 +18528,7 @@ CoreStringNames::CoreStringNames() : } #line 0 -#line 1 "sfwl/object/dictionary.cpp" +#line 1 "sfw/object/dictionary.cpp" /*************************************************************************/ /* dictionary.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -14091,7 +18822,7 @@ Dictionary::~Dictionary() { } #line 0 -#line 1 "sfwl/object/array.cpp" +#line 1 "sfw/object/array.cpp" /*************************************************************************/ /* array.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -14852,7 +19583,7 @@ Array::~Array() { } #line 0 -#line 1 "sfwl/object/psignal.cpp" +#line 1 "sfw/object/psignal.cpp" void Signal::connect_static(void (*func)(Signal *)) { StaticSignalEntry *se = new StaticSignalEntry(); @@ -14972,7 +19703,7 @@ Signal::~Signal() { } #line 0 -#line 1 "sfwl/object/variant.cpp" +#line 1 "sfw/object/variant.cpp" /*************************************************************************/ /* variant.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -15001,12 +19732,52 @@ String Variant::get_type_name(Variant::Type p_type) { } break; // math types + case RECT2: { + return "Rect2"; + } break; case RECT2I: { return "Rect2i"; } break; + case VECTOR2: { + return "Vector2"; + } break; case VECTOR2I: { return "Vector2i"; } break; + case VECTOR3: { + return "Vector3"; + } break; + case VECTOR3I: { + return "Vector3i"; + } break; + case VECTOR4: { + return "Vector4"; + } break; + case VECTOR4I: { + return "Vector4i"; + } break; + + case PLANE: { + return "Plane"; + } break; + case QUATERNION: { + return "Quaternion"; + } break; + case AABB: { + return "AABB"; + } break; + case BASIS: { + return "Basis"; + } break; + case TRANSFORM: { + return "Transform"; + } break; + case TRANSFORM2D: { + return "Transform2D"; + } break; + case PROJECTION: { + return "Projection"; + } break; // misc types case COLOR: { @@ -15038,9 +19809,24 @@ String Variant::get_type_name(Variant::Type p_type) { case POOL_STRING_ARRAY: { return "PoolStringArray"; } break; + case POOL_VECTOR2_ARRAY: { + return "PoolVector2Array"; + } break; case POOL_VECTOR2I_ARRAY: { return "PoolVector2iArray"; } break; + case POOL_VECTOR3_ARRAY: { + return "PoolVector3Array"; + } break; + case POOL_VECTOR3I_ARRAY: { + return "PoolVector3iArray"; + } break; + case POOL_VECTOR4_ARRAY: { + return "PoolVector4Array"; + } break; + case POOL_VECTOR4I_ARRAY: { + return "PoolVector4iArray"; + } break; case POOL_COLOR_ARRAY: { return "PoolColorArray"; } break; @@ -15108,8 +19894,25 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { invalid_types = invalid; } break; + case RECT2: { + static const Type valid[] = { + RECT2I, + NIL + }; + + valid_types = valid; + } break; case RECT2I: { static const Type valid[] = { + RECT2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2: { + static const Type valid[] = { + VECTOR2I, NIL }; @@ -15117,6 +19920,88 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case VECTOR2I: { static const Type valid[] = { + VECTOR2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3: { + static const Type valid[] = { + VECTOR3I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3I: { + static const Type valid[] = { + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4: { + static const Type valid[] = { + VECTOR4I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4I: { + static const Type valid[] = { + VECTOR4, + NIL + }; + + valid_types = valid; + } break; + case PLANE: { + //can't + } break; + case QUATERNION: { + static const Type valid[] = { + BASIS, + NIL + }; + + valid_types = valid; + } break; + case AABB: { + //can't + } break; + case BASIS: { + static const Type valid[] = { + QUATERNION, + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM: { + static const Type valid[] = { + TRANSFORM2D, + QUATERNION, + BASIS, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM2D: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case PROJECTION: { + static const Type valid[] = { + TRANSFORM, NIL }; @@ -15157,7 +20042,10 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { POOL_STRING_ARRAY, POOL_REAL_ARRAY, POOL_COLOR_ARRAY, + POOL_VECTOR2_ARRAY, POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, NIL }; @@ -15194,6 +20082,13 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { }; valid_types = valid; } break; + case POOL_VECTOR2_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; case POOL_VECTOR2I_ARRAY: { static const Type valid[] = { ARRAY, @@ -15201,6 +20096,34 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { }; valid_types = valid; } break; + case POOL_VECTOR3_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR3I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR4_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR4I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; case POOL_COLOR_ARRAY: { static const Type valid[] = { ARRAY, @@ -15295,8 +20218,25 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case RECT2: { + static const Type valid[] = { + RECT2I, + NIL + }; + + valid_types = valid; + } break; case RECT2I: { static const Type valid[] = { + RECT2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2: { + static const Type valid[] = { + VECTOR2I, NIL }; @@ -15304,6 +20244,88 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case VECTOR2I: { static const Type valid[] = { + VECTOR2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3: { + static const Type valid[] = { + VECTOR3I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3I: { + static const Type valid[] = { + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4: { + static const Type valid[] = { + VECTOR4I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4I: { + static const Type valid[] = { + VECTOR4, + NIL + }; + + valid_types = valid; + } break; + case PLANE: { + //Can't + } break; + case QUATERNION: { + static const Type valid[] = { + BASIS, + NIL + }; + + valid_types = valid; + } break; + case AABB: { + //Can't + } break; + case BASIS: { + static const Type valid[] = { + QUATERNION, + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM: { + static const Type valid[] = { + TRANSFORM2D, + QUATERNION, + BASIS, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM2D: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case PROJECTION: { + static const Type valid[] = { + TRANSFORM, NIL }; @@ -15343,7 +20365,12 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type POOL_STRING_ARRAY, POOL_REAL_ARRAY, POOL_COLOR_ARRAY, + POOL_VECTOR2_ARRAY, POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, + POOL_VECTOR4_ARRAY, + POOL_VECTOR4I_ARRAY, NIL }; @@ -15381,6 +20408,14 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case POOL_VECTOR2_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; case POOL_VECTOR2I_ARRAY: { static const Type valid[] = { ARRAY, @@ -15389,6 +20424,38 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case POOL_VECTOR3_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR3I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR4_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR4I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; case POOL_COLOR_ARRAY: { static const Type valid[] = { ARRAY, @@ -15496,12 +20563,52 @@ bool Variant::is_zero() const { } break; // math types + case RECT2: { + return *reinterpret_cast(_data._mem) == Rect2(); + } break; case RECT2I: { return *reinterpret_cast(_data._mem) == Rect2i(); } break; + case VECTOR2: { + return *reinterpret_cast(_data._mem) == Vector2(); + } break; case VECTOR2I: { return *reinterpret_cast(_data._mem) == Vector2i(); } break; + case VECTOR3: { + return *reinterpret_cast(_data._mem) == Vector3(); + } break; + case VECTOR3I: { + return *reinterpret_cast(_data._mem) == Vector3i(); + } break; + case VECTOR4: { + return *reinterpret_cast(_data._mem) == Vector4(); + } break; + case VECTOR4I: { + return *reinterpret_cast(_data._mem) == Vector4i(); + } break; + + case PLANE: { + return *reinterpret_cast(_data._mem) == Plane(); + } break; + case QUATERNION: { + return *reinterpret_cast(_data._mem) == Quaternion(); + } break; + case AABB: { + return *_data._aabb == ::AABB(); + } break; + case BASIS: { + return *_data._basis == Basis(); + } break; + case TRANSFORM: { + return *_data._transform == Transform(); + } break; + case TRANSFORM2D: { + return *_data._transform2d == Transform2D(); + } break; + case PROJECTION: { + return *_data._projection == Projection(); + } break; // misc types case COLOR: { @@ -15533,9 +20640,24 @@ bool Variant::is_zero() const { case POOL_STRING_ARRAY: { return reinterpret_cast *>(_data._mem)->size() == 0; } break; + case POOL_VECTOR2_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; case POOL_VECTOR2I_ARRAY: { return reinterpret_cast *>(_data._mem)->size() == 0; } break; + case POOL_VECTOR3_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR3I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR4_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR4I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; case POOL_COLOR_ARRAY: { return reinterpret_cast *>(_data._mem)->size() == 0; } break; @@ -15562,12 +20684,33 @@ bool Variant::is_one() const { case REAL: { return _data._real == 1; } break; + case RECT2: { + return *reinterpret_cast(_data._mem) == Rect2(1, 1, 1, 1); + } break; case RECT2I: { return *reinterpret_cast(_data._mem) == Rect2i(1, 1, 1, 1); } break; + case VECTOR2: { + return *reinterpret_cast(_data._mem) == Vector2(1, 1); + } break; case VECTOR2I: { return *reinterpret_cast(_data._mem) == Vector2i(1, 1); } break; + case VECTOR3: { + return *reinterpret_cast(_data._mem) == Vector3(1, 1, 1); + } break; + case VECTOR3I: { + return *reinterpret_cast(_data._mem) == Vector3i(1, 1, 1); + } break; + case VECTOR4: { + return *reinterpret_cast(_data._mem) == Vector4(1, 1, 1, 1); + } break; + case VECTOR4I: { + return *reinterpret_cast(_data._mem) == Vector4i(1, 1, 1, 1); + } break; + case PLANE: { + return *reinterpret_cast(_data._mem) == Plane(1, 1, 1, 1); + } break; case COLOR: { return *reinterpret_cast(_data._mem) == Color(1, 1, 1, 1); } break; @@ -15629,12 +20772,52 @@ void Variant::reference(const Variant &p_variant) { } break; // math types + case RECT2: { + memnew_placement(_data._mem, Rect2(*reinterpret_cast(p_variant._data._mem))); + } break; case RECT2I: { memnew_placement(_data._mem, Rect2i(*reinterpret_cast(p_variant._data._mem))); } break; + case VECTOR2: { + memnew_placement(_data._mem, Vector2(*reinterpret_cast(p_variant._data._mem))); + } break; case VECTOR2I: { memnew_placement(_data._mem, Vector2i(*reinterpret_cast(p_variant._data._mem))); } break; + case VECTOR3: { + memnew_placement(_data._mem, Vector3(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR3I: { + memnew_placement(_data._mem, Vector3i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR4: { + memnew_placement(_data._mem, Vector4(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR4I: { + memnew_placement(_data._mem, Vector4i(*reinterpret_cast(p_variant._data._mem))); + } break; + + case PLANE: { + memnew_placement(_data._mem, Plane(*reinterpret_cast(p_variant._data._mem))); + } break; + case QUATERNION: { + memnew_placement(_data._mem, Quaternion(*reinterpret_cast(p_variant._data._mem))); + } break; + case AABB: { + _data._aabb = memnew(::AABB(*p_variant._data._aabb)); + } break; + case BASIS: { + _data._basis = memnew(Basis(*p_variant._data._basis)); + } break; + case TRANSFORM: { + _data._transform = memnew(Transform(*p_variant._data._transform)); + } break; + case TRANSFORM2D: { + _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); + } break; + case PROJECTION: { + _data._projection = memnew(Projection(*p_variant._data._projection)); + } break; // misc types case COLOR: { @@ -15669,9 +20852,24 @@ void Variant::reference(const Variant &p_variant) { case POOL_STRING_ARRAY: { memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); } break; + case POOL_VECTOR2_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; case POOL_VECTOR2I_ARRAY: { memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); } break; + case POOL_VECTOR3_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR3I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR4_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR4I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; case POOL_COLOR_ARRAY: { memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); } break; @@ -15693,15 +20891,45 @@ void Variant::zero() { case REAL: this->_data._real = 0; break; + case RECT2: + *reinterpret_cast(this->_data._mem) = Rect2(); + break; case RECT2I: *reinterpret_cast(this->_data._mem) = Rect2i(); break; + case VECTOR2: + *reinterpret_cast(this->_data._mem) = Vector2(); + break; case VECTOR2I: *reinterpret_cast(this->_data._mem) = Vector2i(); break; + case VECTOR3: + *reinterpret_cast(this->_data._mem) = Vector3(); + break; + case VECTOR3I: + *reinterpret_cast(this->_data._mem) = Vector3i(); + break; + case VECTOR4: + *reinterpret_cast(this->_data._mem) = Vector4(); + break; + case VECTOR4I: + *reinterpret_cast(this->_data._mem) = Vector4i(); + break; + case PLANE: + *reinterpret_cast(this->_data._mem) = Plane(); + break; + case QUATERNION: + *reinterpret_cast(this->_data._mem) = Quaternion(); + break; + case AABB: + *reinterpret_cast<::AABB *>(this->_data._mem) = ::AABB(); + break; case COLOR: *reinterpret_cast(this->_data._mem) = Color(); break; + case PROJECTION: + *reinterpret_cast(this->_data._mem) = Projection(); + break; default: this->clear(); break; @@ -15732,6 +20960,21 @@ void Variant::clear() { PLANE, QUATERNION, */ + case AABB: { + memdelete(_data._aabb); + } break; + case BASIS: { + memdelete(_data._basis); + } break; + case TRANSFORM: { + memdelete(_data._transform); + } break; + case TRANSFORM2D: { + memdelete(_data._transform2d); + } break; + case PROJECTION: { + memdelete(_data._projection); + } break; //COLOR // misc types @@ -15767,9 +21010,24 @@ void Variant::clear() { case POOL_STRING_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); } break; + case POOL_VECTOR2_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; case POOL_VECTOR2I_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); } break; + case POOL_VECTOR3_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR3I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR4_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR4I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; case POOL_COLOR_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); } break; @@ -16069,10 +21327,38 @@ String Variant::stringify(List &stack) const { return rtos(_data._real); case STRING: return *reinterpret_cast(_data._mem); + case RECT2: + return operator Rect2(); case RECT2I: return operator Rect2i(); + case VECTOR2: + return operator Vector2(); case VECTOR2I: return operator Vector2i(); + case VECTOR3: + return operator Vector3(); + case VECTOR3I: + return operator Vector3i(); + case VECTOR4: + return operator Vector4(); + case VECTOR4I: + return operator Vector4i(); + case PLANE: + return operator Plane(); + case QUATERNION: + return operator Quaternion(); + case AABB: + return operator ::AABB(); + case BASIS: { + return operator Basis(); + } break; + case TRANSFORM: + return operator Transform(); + case TRANSFORM2D: { + return operator Transform2D(); + } break; + case PROJECTION: + return operator Projection(); case COLOR: return operator Color(); case OBJECT: { @@ -16148,9 +21434,24 @@ String Variant::stringify(List &stack) const { case POOL_STRING_ARRAY: { return stringify_vector(operator PoolVector(), stack); } break; + case POOL_VECTOR2_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; case POOL_VECTOR2I_ARRAY: { return stringify_vector(operator PoolVector(), stack); } break; + case POOL_VECTOR3_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR3I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR4_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR4I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; case POOL_COLOR_ARRAY: { return stringify_vector(operator PoolVector(), stack); } break; @@ -16163,22 +21464,239 @@ String Variant::stringify(List &stack) const { return ""; } +Variant::operator Rect2() const { + if (type == RECT2) { + return *reinterpret_cast(_data._mem); + } else if (type == RECT2I) { + return Rect2(*reinterpret_cast(_data._mem)); + } else { + return Rect2(); + } +} Variant::operator Rect2i() const { if (type == RECT2I) { return *reinterpret_cast(_data._mem); + } else if (type == RECT2) { + return Rect2i(*reinterpret_cast(_data._mem)); } else { return Rect2i(); } } +Variant::operator Vector2() const { + if (type == VECTOR2) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else { + return Vector2(); + } +} Variant::operator Vector2i() const { if (type == VECTOR2I) { return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3I) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4I) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); } else { return Vector2i(); } } +Variant::operator Vector3() const { + if (type == VECTOR3) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3I) { + return Vector3(*reinterpret_cast(_data._mem)); + } else if (type == VECTOR2) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR2I) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR4) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR4I) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else { + return Vector3(); + } +} +Variant::operator Vector3i() const { + if (type == VECTOR3I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR2) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR2I) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR4) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR4I) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else { + return Vector3i(); + } +} + +Variant::operator Vector4() const { + if (type == VECTOR4) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR4I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR2I) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR3) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else if (type == VECTOR3I) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else { + return Vector4(); + } +} + +Variant::operator Vector4i() const { + if (type == VECTOR4I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR4) { + const Vector4 &v4 = *reinterpret_cast(_data._mem); + return Vector4i(v4.x, v4.y, v4.z, v4.w); + } else if (type == VECTOR2) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR2I) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR3) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else if (type == VECTOR3I) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else { + return Vector4i(); + } +} + +Variant::operator Plane() const { + if (type == PLANE) { + return *reinterpret_cast(_data._mem); + } else { + return Plane(); + } +} +Variant::operator ::AABB() const { + if (type == AABB) { + return *_data._aabb; + } else { + return ::AABB(); + } +} + +Variant::operator Basis() const { + if (type == BASIS) { + return *_data._basis; + } else if (type == QUATERNION) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3) { + return Basis(*reinterpret_cast(_data._mem)); + } else if (type == TRANSFORM) { // unexposed in Variant::can_convert? + return _data._transform->basis; + } else { + return Basis(); + } +} + +Variant::operator Quaternion() const { + if (type == QUATERNION) { + return *reinterpret_cast(_data._mem); + } else if (type == BASIS) { + return *_data._basis; + } else if (type == TRANSFORM) { + return _data._transform->basis; + } else { + return Quaternion(); + } +} + +Variant::operator Transform2D() const { + if (type == TRANSFORM2D) { + return *_data._transform2d; + } else if (type == TRANSFORM) { + const Transform &t = *_data._transform; + Transform2D m; + m.columns[0][0] = t.basis.rows[0][0]; + m.columns[0][1] = t.basis.rows[1][0]; + m.columns[1][0] = t.basis.rows[0][1]; + m.columns[1][1] = t.basis.rows[1][1]; + m.columns[2][0] = t.origin[0]; + m.columns[2][1] = t.origin[1]; + return m; + } else { + return Transform2D(); + } +} + +Variant::operator Transform() const { + if (type == TRANSFORM) { + return *_data._transform; + } else if (type == BASIS) { + return Transform(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform(Basis(*reinterpret_cast(_data._mem)), Vector3()); + } else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.rows[0][0] = t.columns[0][0]; + m.basis.rows[1][0] = t.columns[0][1]; + m.basis.rows[0][1] = t.columns[1][0]; + m.basis.rows[1][1] = t.columns[1][1]; + m.origin[0] = t.columns[2][0]; + m.origin[1] = t.columns[2][1]; + return m; + } else if (type == PROJECTION) { + return *_data._projection; + } else { + return Transform(); + } +} + +Variant::operator Projection() const { + if (type == TRANSFORM) { + return *_data._transform; + } else if (type == BASIS) { + return Transform(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform(Basis(*reinterpret_cast(_data._mem)), Vector3()); + } else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.rows[0][0] = t.columns[0][0]; + m.basis.rows[1][0] = t.columns[0][1]; + m.basis.rows[0][1] = t.columns[1][0]; + m.basis.rows[1][1] = t.columns[1][1]; + m.origin[0] = t.columns[2][0]; + m.origin[1] = t.columns[2][1]; + return m; + } else if (type == PROJECTION) { + return *_data._projection; + } else { + return Projection(); + } +} + Variant::operator Color() const { if (type == COLOR) { return *reinterpret_cast(_data._mem); @@ -16237,9 +21755,24 @@ inline DA _convert_array_from_variant(const Variant &p_variant) { case Variant::POOL_STRING_ARRAY: { return _convert_array>(p_variant.operator PoolVector()); } + case Variant::POOL_VECTOR2_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } case Variant::POOL_VECTOR2I_ARRAY: { return _convert_array>(p_variant.operator PoolVector()); } + case Variant::POOL_VECTOR3_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR3I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR4_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR4I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } case Variant::POOL_COLOR_ARRAY: { return _convert_array>(p_variant.operator PoolVector()); } @@ -16294,6 +21827,13 @@ Variant::operator PoolVector() const { return _convert_array_from_variant>(*this); } } +Variant::operator PoolVector() const { + if (type == POOL_VECTOR2_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} Variant::operator PoolVector() const { if (type == POOL_VECTOR2I_ARRAY) { return *reinterpret_cast *>(_data._mem); @@ -16301,6 +21841,34 @@ Variant::operator PoolVector() const { return _convert_array_from_variant>(*this); } } +Variant::operator PoolVector() const { + if (type == POOL_VECTOR3_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR3I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR4_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR4I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} Variant::operator PoolVector() const { if (type == POOL_COLOR_ARRAY) { return *reinterpret_cast *>(_data._mem); @@ -16311,6 +21879,60 @@ Variant::operator PoolVector() const { /* helpers */ +Variant::operator PoolVector() const { + Array va = operator Array(); + PoolVector planes; + int va_size = va.size(); + if (va_size == 0) { + return planes; + } + + planes.resize(va_size); + PoolVector::Write w = planes.write(); + + for (int i = 0; i < va_size; i++) { + w[i] = va[i]; + } + + return planes; +} + +Variant::operator PoolVector() const { + PoolVector va = operator PoolVector(); + PoolVector faces; + int va_size = va.size(); + if (va_size == 0) { + return faces; + } + + faces.resize(va_size / 3); + PoolVector::Write w = faces.write(); + PoolVector::Read r = va.read(); + + for (int i = 0; i < va_size; i++) { + w[i / 3].vertex[i % 3] = r[i]; + } + + return faces; +} + +Variant::operator Vector() const { + Array va = operator Array(); + Vector planes; + int va_size = va.size(); + if (va_size == 0) { + return planes; + } + + planes.resize(va_size); + + for (int i = 0; i < va_size; i++) { + planes.write[i] = va[i]; + } + + return planes; +} + Variant::operator Vector() const { Array from = operator Array(); Vector to; @@ -16374,6 +21996,21 @@ Variant::operator Vector() const { return to; } +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector2 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} Variant::operator Vector() const { PoolVector from = operator PoolVector(); Vector to; @@ -16390,6 +22027,68 @@ Variant::operator Vector() const { return to; } +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector3 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector3i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector4 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector4i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + Variant::operator Vector() const { PoolVector from = operator PoolVector(); Vector to; @@ -16504,16 +22203,75 @@ Variant::Variant(const CharType *p_wstring) { memnew_placement(_data._mem, String(p_wstring)); } +Variant::Variant(const Rect2 &p_rect2) { + type = RECT2; + memnew_placement(_data._mem, Rect2(p_rect2)); +} Variant::Variant(const Rect2i &p_rect2) { type = RECT2I; memnew_placement(_data._mem, Rect2i(p_rect2)); } +Variant::Variant(const Vector2 &p_vector2) { + type = VECTOR2; + memnew_placement(_data._mem, Vector2(p_vector2)); +} Variant::Variant(const Vector2i &p_vector2) { type = VECTOR2I; memnew_placement(_data._mem, Vector2i(p_vector2)); } +Variant::Variant(const Vector3 &p_vector3) { + type = VECTOR3; + memnew_placement(_data._mem, Vector3(p_vector3)); +} +Variant::Variant(const Vector3i &p_vector3) { + type = VECTOR3I; + memnew_placement(_data._mem, Vector3i(p_vector3)); +} + +Variant::Variant(const Vector4 &p_vector4) { + type = VECTOR4; + memnew_placement(_data._mem, Vector4(p_vector4)); +} +Variant::Variant(const Vector4i &p_vector4) { + type = VECTOR4I; + memnew_placement(_data._mem, Vector4i(p_vector4)); +} + +Variant::Variant(const Plane &p_plane) { + type = PLANE; + memnew_placement(_data._mem, Plane(p_plane)); +} +Variant::Variant(const ::AABB &p_aabb) { + type = AABB; + _data._aabb = memnew(::AABB(p_aabb)); +} + +Variant::Variant(const Basis &p_matrix) { + type = BASIS; + _data._basis = memnew(Basis(p_matrix)); +} + +Variant::Variant(const Quaternion &p_quat) { + type = QUATERNION; + memnew_placement(_data._mem, Quaternion(p_quat)); +} +Variant::Variant(const Transform &p_transform) { + type = TRANSFORM; + _data._transform = memnew(Transform(p_transform)); +} + +Variant::Variant(const Transform2D &p_transform) { + type = TRANSFORM2D; + _data._transform2d = memnew(Transform2D(p_transform)); +} + +Variant::Variant(const Projection &p_projection) { + type = PROJECTION; + _data._projection = memnew(Projection(p_projection)); +} + Variant::Variant(const Color &p_color) { type = COLOR; memnew_placement(_data._mem, Color(p_color)); @@ -16550,6 +22308,30 @@ Variant::Variant(const Array &p_array) { memnew_placement(_data._mem, Array(p_array)); } +Variant::Variant(const PoolVector &p_array) { + type = ARRAY; + + Array *plane_array = memnew_placement(_data._mem, Array); + + plane_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + plane_array->operator[](i) = Variant(p_array[i]); + } +} + +Variant::Variant(const Vector &p_array) { + type = ARRAY; + + Array *plane_array = memnew_placement(_data._mem, Array); + + plane_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + plane_array->operator[](i) = Variant(p_array[i]); + } +} + Variant::Variant(const PoolVector &p_raw_array) { type = POOL_BYTE_ARRAY; memnew_placement(_data._mem, PoolVector(p_raw_array)); @@ -16566,16 +22348,58 @@ Variant::Variant(const PoolVector &p_string_array) { type = POOL_STRING_ARRAY; memnew_placement(_data._mem, PoolVector(p_string_array)); } +Variant::Variant(const PoolVector &p_vector2_array) { + type = POOL_VECTOR2_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector2_array)); +} Variant::Variant(const PoolVector &p_vector2_array) { type = POOL_VECTOR2I_ARRAY; memnew_placement(_data._mem, PoolVector(p_vector2_array)); } +Variant::Variant(const PoolVector &p_vector3_array) { + type = POOL_VECTOR3_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector3_array)); +} +Variant::Variant(const PoolVector &p_vector3_array) { + type = POOL_VECTOR3I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector3_array)); +} + +Variant::Variant(const PoolVector &p_vector4_array) { + type = POOL_VECTOR4_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector4_array)); +} +Variant::Variant(const PoolVector &p_vector4_array) { + type = POOL_VECTOR4I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector4_array)); +} Variant::Variant(const PoolVector &p_color_array) { type = POOL_COLOR_ARRAY; memnew_placement(_data._mem, PoolVector(p_color_array)); } +Variant::Variant(const PoolVector &p_face_array) { + PoolVector vertices; + int face_count = p_face_array.size(); + vertices.resize(face_count * 3); + + if (face_count) { + PoolVector::Read r = p_face_array.read(); + PoolVector::Write w = vertices.write(); + + for (int i = 0; i < face_count; i++) { + for (int j = 0; j < 3; j++) { + w[i * 3 + j] = r[i].vertex[j]; + } + } + } + + type = NIL; + + *this = vertices; +} + /* helpers */ Variant::Variant(const Vector &p_array) { @@ -16644,6 +22468,21 @@ Variant::Variant(const Vector &p_array) { *this = v; } +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector2 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} Variant::Variant(const Vector &p_array) { type = NIL; PoolVector v; @@ -16660,6 +22499,68 @@ Variant::Variant(const Vector &p_array) { *this = v; } +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector3 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector3i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector4 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector4i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + Variant::Variant(const Vector &p_array) { type = NIL; PoolVector v; @@ -16701,12 +22602,52 @@ void Variant::operator=(const Variant &p_variant) { } break; // math types + case RECT2: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; case RECT2I: { *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); } break; + case VECTOR2: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; case VECTOR2I: { *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); } break; + case VECTOR3: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR3I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR4: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR4I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + case PLANE: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case QUATERNION: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case AABB: { + *_data._aabb = *(p_variant._data._aabb); + } break; + case BASIS: { + *_data._basis = *(p_variant._data._basis); + } break; + case TRANSFORM: { + *_data._transform = *(p_variant._data._transform); + } break; + case TRANSFORM2D: { + *_data._transform2d = *(p_variant._data._transform2d); + } break; + case PROJECTION: { + *_data._projection = *(p_variant._data._projection); + } break; // misc types case COLOR: { @@ -16746,9 +22687,24 @@ void Variant::operator=(const Variant &p_variant) { case POOL_STRING_ARRAY: { *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); } break; + case POOL_VECTOR2_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; case POOL_VECTOR2I_ARRAY: { *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); } break; + case POOL_VECTOR3_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR3I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR4_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR4I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; case POOL_COLOR_ARRAY: { *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); } break; @@ -16792,12 +22748,115 @@ uint32_t Variant::recursive_hash(int p_recursion_count) const { } break; // math types + case RECT2: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; case RECT2I: { return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); } break; + case VECTOR2: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; case VECTOR2I: { return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); } break; + case VECTOR3: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR3I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR4: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR4I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case PLANE: { + uint32_t h = HASH_MURMUR3_SEED; + const Plane &p = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_real(p.normal.x, h); + h = hash_murmur3_one_real(p.normal.y, h); + h = hash_murmur3_one_real(p.normal.z, h); + h = hash_murmur3_one_real(p.d, h); + return hash_fmix32(h); + } break; + case QUATERNION: { + uint32_t h = HASH_MURMUR3_SEED; + const Quaternion &q = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_real(q.x, h); + h = hash_murmur3_one_real(q.y, h); + h = hash_murmur3_one_real(q.z, h); + h = hash_murmur3_one_real(q.w, h); + return hash_fmix32(h); + } break; + case AABB: { + return HashMapHasherDefault::hash(*_data._aabb); + } break; + case BASIS: { + uint32_t h = HASH_MURMUR3_SEED; + const Basis &b = *_data._basis; + h = hash_murmur3_one_real(b[0].x, h); + h = hash_murmur3_one_real(b[0].y, h); + h = hash_murmur3_one_real(b[0].z, h); + h = hash_murmur3_one_real(b[1].x, h); + h = hash_murmur3_one_real(b[1].y, h); + h = hash_murmur3_one_real(b[1].z, h); + h = hash_murmur3_one_real(b[2].x, h); + h = hash_murmur3_one_real(b[2].y, h); + h = hash_murmur3_one_real(b[2].z, h); + return hash_fmix32(h); + } break; + case TRANSFORM: { + uint32_t h = HASH_MURMUR3_SEED; + const Transform &t = *_data._transform; + h = hash_murmur3_one_real(t.basis[0].x, h); + h = hash_murmur3_one_real(t.basis[0].y, h); + h = hash_murmur3_one_real(t.basis[0].z, h); + h = hash_murmur3_one_real(t.basis[1].x, h); + h = hash_murmur3_one_real(t.basis[1].y, h); + h = hash_murmur3_one_real(t.basis[1].z, h); + h = hash_murmur3_one_real(t.basis[2].x, h); + h = hash_murmur3_one_real(t.basis[2].y, h); + h = hash_murmur3_one_real(t.basis[2].z, h); + h = hash_murmur3_one_real(t.origin.x, h); + h = hash_murmur3_one_real(t.origin.y, h); + h = hash_murmur3_one_real(t.origin.z, h); + return hash_fmix32(h); + } break; + case TRANSFORM2D: { + uint32_t h = HASH_MURMUR3_SEED; + const Transform2D &t = *_data._transform2d; + h = hash_murmur3_one_real(t[0].x, h); + h = hash_murmur3_one_real(t[0].y, h); + h = hash_murmur3_one_real(t[1].x, h); + h = hash_murmur3_one_real(t[1].y, h); + h = hash_murmur3_one_real(t[2].x, h); + h = hash_murmur3_one_real(t[2].y, h); + + return hash_fmix32(h); + } break; + case PROJECTION: { + uint32_t h = HASH_MURMUR3_SEED; + const Projection &t = *_data._projection; + h = hash_murmur3_one_real(t.matrix[0].x, h); + h = hash_murmur3_one_real(t.matrix[0].y, h); + h = hash_murmur3_one_real(t.matrix[0].z, h); + h = hash_murmur3_one_real(t.matrix[0].w, h); + h = hash_murmur3_one_real(t.matrix[1].x, h); + h = hash_murmur3_one_real(t.matrix[1].y, h); + h = hash_murmur3_one_real(t.matrix[1].z, h); + h = hash_murmur3_one_real(t.matrix[1].w, h); + h = hash_murmur3_one_real(t.matrix[2].x, h); + h = hash_murmur3_one_real(t.matrix[2].y, h); + h = hash_murmur3_one_real(t.matrix[2].z, h); + h = hash_murmur3_one_real(t.matrix[2].w, h); + h = hash_murmur3_one_real(t.matrix[3].x, h); + h = hash_murmur3_one_real(t.matrix[3].y, h); + h = hash_murmur3_one_real(t.matrix[3].z, h); + h = hash_murmur3_one_real(t.matrix[3].w, h); + return hash_fmix32(h); + } break; // misc types case COLOR: { @@ -16880,6 +22939,24 @@ uint32_t Variant::recursive_hash(int p_recursion_count) const { return hash; } break; + case POOL_VECTOR2_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; case POOL_VECTOR2I_ARRAY: { uint32_t hash = HASH_MURMUR3_SEED; const PoolVector &arr = *reinterpret_cast *>(_data._mem); @@ -16898,7 +22975,84 @@ uint32_t Variant::recursive_hash(int p_recursion_count) const { return hash; } break; + case POOL_VECTOR3_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR3I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + hash = hash_murmur3_one_32(r[i].z, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR4_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); + hash = hash_murmur3_one_real(r[i].w, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR4I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + hash = hash_murmur3_one_32(r[i].z, hash); + hash = hash_murmur3_one_32(r[i].w, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; case POOL_COLOR_ARRAY: { uint32_t hash = HASH_MURMUR3_SEED; const PoolVector &arr = *reinterpret_cast *>(_data._mem); @@ -17005,6 +23159,13 @@ bool Variant::hash_compare(const Variant &p_variant) const { return *reinterpret_cast(_data._mem) == *reinterpret_cast(p_variant._data._mem); } break; + case RECT2: { + const Rect2 *l = reinterpret_cast(_data._mem); + const Rect2 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2(l->position, r->position) && + hash_compare_vector2(l->size, r->size); + } break; case RECT2I: { const Rect2i *l = reinterpret_cast(_data._mem); const Rect2i *r = reinterpret_cast(p_variant._data._mem); @@ -17012,12 +23173,112 @@ bool Variant::hash_compare(const Variant &p_variant) const { return hash_compare_vector2i(l->position, r->position) && hash_compare_vector2i(l->size, r->size); } break; + case VECTOR2: { + const Vector2 *l = reinterpret_cast(_data._mem); + const Vector2 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2(*l, *r); + } break; case VECTOR2I: { const Vector2i *l = reinterpret_cast(_data._mem); const Vector2i *r = reinterpret_cast(p_variant._data._mem); return hash_compare_vector2i(*l, *r); } break; + case VECTOR3: { + const Vector3 *l = reinterpret_cast(_data._mem); + const Vector3 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3(*l, *r); + } break; + case VECTOR3I: { + const Vector3i *l = reinterpret_cast(_data._mem); + const Vector3i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3i(*l, *r); + } break; + case VECTOR4: { + const Vector4 *l = reinterpret_cast(_data._mem); + const Vector4 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector4(*l, *r); + } break; + case VECTOR4I: { + const Vector4i *l = reinterpret_cast(_data._mem); + const Vector4i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector4i(*l, *r); + } break; + + case PLANE: { + const Plane *l = reinterpret_cast(_data._mem); + const Plane *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3(l->normal, r->normal) && + hash_compare_scalar(l->d, r->d); + } break; + case QUATERNION: { + const Quaternion *l = reinterpret_cast(_data._mem); + const Quaternion *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_quat(*l, *r); + } break; + case AABB: { + const ::AABB *l = _data._aabb; + const ::AABB *r = p_variant._data._aabb; + + return hash_compare_vector3(l->position, r->position) && + hash_compare_vector3(l->size, r->size); + + } break; + case BASIS: { + const Basis *l = _data._basis; + const Basis *r = p_variant._data._basis; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector3(l->rows[i], r->rows[i])) { + return false; + } + } + + return true; + } break; + case TRANSFORM: { + const Transform *l = _data._transform; + const Transform *r = p_variant._data._transform; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector3(l->basis.rows[i], r->basis.rows[i])) { + return false; + } + } + + return hash_compare_vector3(l->origin, r->origin); + } break; + case TRANSFORM2D: { + Transform2D *l = _data._transform2d; + Transform2D *r = p_variant._data._transform2d; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector2(l->columns[i], r->columns[i])) { + return false; + } + } + + return true; + } break; + case PROJECTION: { + const Projection *l = _data._projection; + const Projection *r = p_variant._data._projection; + + for (int i = 0; i < 4; i++) { + if (!hash_compare_vector4(l->matrix[i], r->matrix[i])) { + return false; + } + } + + return true; + } break; case COLOR: { const Color *l = reinterpret_cast(_data._mem); @@ -17045,9 +23306,24 @@ bool Variant::hash_compare(const Variant &p_variant) const { case POOL_REAL_ARRAY: { hash_compare_pool_array(_data._mem, p_variant._data._mem, real_t, hash_compare_scalar); } break; + case POOL_VECTOR2_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector2, hash_compare_vector2); + } break; case POOL_VECTOR2I_ARRAY: { hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector2i, hash_compare_vector2i); } break; + case POOL_VECTOR3_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector3, hash_compare_vector3); + } break; + case POOL_VECTOR3I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector3i, hash_compare_vector3i); + } break; + case POOL_VECTOR4_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector4, hash_compare_vector4); + } break; + case POOL_VECTOR4I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector4i, hash_compare_vector4i); + } break; case POOL_COLOR_ARRAY: { hash_compare_pool_array(_data._mem, p_variant._data._mem, Color, hash_compare_color); } break; @@ -17153,7 +23429,7 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const } #line 0 -#line 1 "sfwl/object/variant_op.cpp" +#line 1 "sfw/object/variant_op.cpp" /*************************************************************************/ /* variant_op.cpp */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -17168,8 +23444,21 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const CASE_TYPE(PREFIX, OP, BOOL) \ CASE_TYPE(PREFIX, OP, REAL) \ CASE_TYPE(PREFIX, OP, STRING) \ + CASE_TYPE(PREFIX, OP, RECT2) \ CASE_TYPE(PREFIX, OP, RECT2I) \ + CASE_TYPE(PREFIX, OP, VECTOR2) \ CASE_TYPE(PREFIX, OP, VECTOR2I) \ + CASE_TYPE(PREFIX, OP, VECTOR3) \ + CASE_TYPE(PREFIX, OP, VECTOR3I) \ + CASE_TYPE(PREFIX, OP, VECTOR4) \ + CASE_TYPE(PREFIX, OP, VECTOR4I) \ + CASE_TYPE(PREFIX, OP, PLANE) \ + CASE_TYPE(PREFIX, OP, QUATERNION) \ + CASE_TYPE(PREFIX, OP, AABB) \ + CASE_TYPE(PREFIX, OP, BASIS) \ + CASE_TYPE(PREFIX, OP, TRANSFORM) \ + CASE_TYPE(PREFIX, OP, TRANSFORM2D) \ + CASE_TYPE(PREFIX, OP, PROJECTION) \ CASE_TYPE(PREFIX, OP, COLOR) \ CASE_TYPE(PREFIX, OP, OBJECT) \ CASE_TYPE(PREFIX, OP, STRING_NAME) \ @@ -17179,7 +23468,12 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const 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_VECTOR2I_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR3_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR3I_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR4_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR4I_ARRAY) \ CASE_TYPE(PREFIX, OP, POOL_COLOR_ARRAY) #ifdef __GNUC__ @@ -17193,8 +23487,21 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const TYPE(PREFIX, OP, INT), \ TYPE(PREFIX, OP, REAL), \ TYPE(PREFIX, OP, STRING), \ + TYPE(PREFIX, OP, RECT2), \ TYPE(PREFIX, OP, RECT2I), \ + TYPE(PREFIX, OP, VECTOR2), \ TYPE(PREFIX, OP, VECTOR2I), \ + TYPE(PREFIX, OP, VECTOR3), \ + TYPE(PREFIX, OP, VECTOR3I), \ + TYPE(PREFIX, OP, VECTOR4), \ + TYPE(PREFIX, OP, VECTOR4I), \ + TYPE(PREFIX, OP, PLANE), \ + TYPE(PREFIX, OP, QUATERNION), \ + TYPE(PREFIX, OP, AABB), \ + TYPE(PREFIX, OP, BASIS), \ + TYPE(PREFIX, OP, TRANSFORM), \ + TYPE(PREFIX, OP, TRANSFORM2D), \ + TYPE(PREFIX, OP, PROJECTION), \ TYPE(PREFIX, OP, COLOR), \ TYPE(PREFIX, OP, OBJECT), \ TYPE(PREFIX, OP, STRING_NAME), \ @@ -17204,13 +23511,18 @@ String vformat(const String &p_text, const Variant &p1, const Variant &p2, const 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_VECTOR2I_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR3_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR3I_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR4_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR4I_ARRAY), \ TYPE(PREFIX, OP, POOL_COLOR_ARRAY), \ } /* clang-format on */ -#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][18] = { \ +#define CASES(PREFIX) static const void *switch_table_##PREFIX[25][38] = { \ TYPES(PREFIX, OP_EQUAL), \ TYPES(PREFIX, OP_NOT_EQUAL), \ TYPES(PREFIX, OP_LESS), \ @@ -17337,14 +23649,26 @@ bool Variant::booleanize() const { _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) { \ - if (p_b.type == INT) \ - _RETURN(p_a._data.m_type m_op p_b._data._int); \ - if (p_b.type == REAL) \ - _RETURN(p_a._data.m_type m_op p_b._data._real); \ - \ - _RETURN_FAIL \ +#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) { \ + if (p_b.type == INT) \ + _RETURN(p_a._data.m_type m_op p_b._data._int); \ + if (p_b.type == REAL) \ + _RETURN(p_a._data.m_type m_op p_b._data._real); \ + if (p_b.type == VECTOR2) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR2I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR3) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR3I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR4) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR4I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + \ + _RETURN_FAIL \ }; #define DEFAULT_OP_STR_REV(m_prefix, m_op_name, m_name, m_op, m_type) \ @@ -17606,8 +23930,21 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NULL(math, OP_EQUAL, INT, ==, _int); DEFAULT_OP_NUM_NULL(math, OP_EQUAL, REAL, ==, _real); DEFAULT_OP_STR_NULL(math, OP_EQUAL, STRING, ==, String); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2, ==, Rect2); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2I, ==, Rect2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2, ==, Vector2); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2I, ==, Vector2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3, ==, Vector3); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3I, ==, Vector3i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR4, ==, Vector4); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR4I, ==, Vector4i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, PLANE, ==, Plane); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, QUATERNION, ==, Quaternion); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, AABB, ==, _aabb); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, BASIS, ==, _basis); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM, ==, _transform); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM2D, ==, _transform2d); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, PROJECTION, ==, _projection); DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, COLOR, ==, Color); DEFAULT_OP_STR_NULL_SN(math, OP_EQUAL, STRING_NAME, ==, StringName); @@ -17615,7 +23952,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR4I_ARRAY, Vector4i); DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_COLOR_ARRAY, Color); } @@ -17688,8 +24030,21 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, INT, !=, _int); DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, REAL, !=, _real); DEFAULT_OP_STR_NULL(math, OP_NOT_EQUAL, STRING, !=, String); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2, !=, Rect2); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2I, !=, Rect2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2, !=, Vector2); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2I, !=, Vector2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3, !=, Vector3); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3I, !=, Vector3i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR4, !=, Vector4); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR4I, !=, Vector4i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, PLANE, !=, Plane); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, QUATERNION, !=, Quaternion); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, AABB, !=, _aabb); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, BASIS, !=, _basis); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM, !=, _transform); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM2D, !=, _transform2d); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, PROJECTION, !=, _projection); DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, COLOR, !=, Color); DEFAULT_OP_STR_NULL_SN(math, OP_NOT_EQUAL, STRING_NAME, !=, StringName); @@ -17697,7 +24052,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_INT_ARRAY, int); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_REAL_ARRAY, real_t); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR2_ARRAY, Vector2); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR4I_ARRAY, Vector4i); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_COLOR_ARRAY, Color); } @@ -17743,17 +24103,35 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, <, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3I, <, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR4, <, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR4I, <, Vector4i); 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, Vector2); DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR4I_ARRAY, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_LESS, PLANE) + CASE_TYPE(math, OP_LESS, QUATERNION) + CASE_TYPE(math, OP_LESS, AABB) + CASE_TYPE(math, OP_LESS, BASIS) + CASE_TYPE(math, OP_LESS, TRANSFORM) + CASE_TYPE(math, OP_LESS, TRANSFORM2D) + CASE_TYPE(math, OP_LESS, PROJECTION) CASE_TYPE(math, OP_LESS, STRING_NAME) CASE_TYPE(math, OP_LESS, COLOR) CASE_TYPE(math, OP_LESS, DICTIONARY) @@ -17770,11 +24148,24 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, <=, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3I, <=, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR4, <=, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR4I, <=, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_LESS_EQUAL, PLANE) + CASE_TYPE(math, OP_LESS_EQUAL, QUATERNION) + CASE_TYPE(math, OP_LESS_EQUAL, AABB) + CASE_TYPE(math, OP_LESS_EQUAL, BASIS) + CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM) + CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM2D) + CASE_TYPE(math, OP_LESS_EQUAL, PROJECTION) CASE_TYPE(math, OP_LESS_EQUAL, COLOR) CASE_TYPE(math, OP_LESS_EQUAL, STRING_NAME) CASE_TYPE(math, OP_LESS_EQUAL, DICTIONARY) @@ -17783,7 +24174,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR4I_ARRAY); CASE_TYPE(math, OP_LESS_EQUAL, POOL_COLOR_ARRAY); _RETURN_FAIL; } @@ -17830,17 +24226,35 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, <, Vector2i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3I, <, Vector3i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR4, <, Vector4); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR4I, <, Vector4i); 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, Vector2); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR4I_ARRAY, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_GREATER, PLANE) + CASE_TYPE(math, OP_GREATER, QUATERNION) + CASE_TYPE(math, OP_GREATER, AABB) + CASE_TYPE(math, OP_GREATER, BASIS) CASE_TYPE(math, OP_GREATER, STRING_NAME) + CASE_TYPE(math, OP_GREATER, TRANSFORM) + CASE_TYPE(math, OP_GREATER, TRANSFORM2D) + CASE_TYPE(math, OP_GREATER, PROJECTION) CASE_TYPE(math, OP_GREATER, COLOR) CASE_TYPE(math, OP_GREATER, DICTIONARY) _RETURN_FAIL; @@ -17856,11 +24270,24 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, <=, Vector2i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3I, <=, Vector3i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR4, <=, Vector4); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR4I, <=, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_GREATER_EQUAL, PLANE) + CASE_TYPE(math, OP_GREATER_EQUAL, QUATERNION) + CASE_TYPE(math, OP_GREATER_EQUAL, AABB) + CASE_TYPE(math, OP_GREATER_EQUAL, BASIS) + CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM) + CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM2D) + CASE_TYPE(math, OP_GREATER_EQUAL, PROJECTION) CASE_TYPE(math, OP_GREATER_EQUAL, COLOR) CASE_TYPE(math, OP_GREATER_EQUAL, DICTIONARY) CASE_TYPE(math, OP_GREATER_EQUAL, STRING_NAME) @@ -17869,7 +24296,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR4I_ARRAY); CASE_TYPE(math, OP_GREATER_EQUAL, POOL_COLOR_ARRAY); _RETURN_FAIL; } @@ -17897,19 +24329,37 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, +, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3, +, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3I, +, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR4, +, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR4I, +, Vector4i); + DEFAULT_OP_LOCALMEM(math, OP_ADD, QUATERNION, +, Quaternion); 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_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR4I_ARRAY, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_ADD, PLANE) + CASE_TYPE(math, OP_ADD, AABB) + CASE_TYPE(math, OP_ADD, BASIS) + CASE_TYPE(math, OP_ADD, TRANSFORM) + CASE_TYPE(math, OP_ADD, TRANSFORM2D) + CASE_TYPE(math, OP_ADD, PROJECTION) CASE_TYPE(math, OP_ADD, OBJECT) CASE_TYPE(math, OP_ADD, DICTIONARY) CASE_TYPE(math, OP_ADD, STRING_NAME) @@ -17919,13 +24369,26 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, -, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3, -, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3I, -, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR4, -, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR4I, -, Vector4i); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, QUATERNION, -, Quaternion); 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, RECT2I) + CASE_TYPE(math, OP_SUBTRACT, PLANE) + CASE_TYPE(math, OP_SUBTRACT, AABB) + CASE_TYPE(math, OP_SUBTRACT, BASIS) + CASE_TYPE(math, OP_SUBTRACT, TRANSFORM) + CASE_TYPE(math, OP_SUBTRACT, TRANSFORM2D) + CASE_TYPE(math, OP_SUBTRACT, PROJECTION) CASE_TYPE(math, OP_SUBTRACT, OBJECT) CASE_TYPE(math, OP_SUBTRACT, STRING_NAME) CASE_TYPE(math, OP_SUBTRACT, DICTIONARY) @@ -17934,21 +24397,120 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR4I_ARRAY); CASE_TYPE(math, OP_SUBTRACT, POOL_COLOR_ARRAY); _RETURN_FAIL; } SWITCH_OP(math, OP_MULTIPLY, p_a.type) { + CASE_TYPE(math, OP_MULTIPLY, QUATERNION) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(reinterpret_cast(p_a._data._mem)->xform(*(const Vector3 *)p_b._data._mem)); + } + case VECTOR3I: { + _RETURN(reinterpret_cast(p_a._data._mem)->xform(*(const Vector3i *)p_b._data._mem)); + } + case QUATERNION: { + _RETURN(*reinterpret_cast(p_a._data._mem) * *reinterpret_cast(p_b._data._mem)); + } + case REAL: { + _RETURN(*reinterpret_cast(p_a._data._mem) * p_b._data._real); + } + default: + _RETURN_FAIL; + } + } + + 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 VECTOR3I: { + _RETURN(p_a._data._basis->xform(*(const Vector3i *)p_b._data._mem)); + } + case BASIS: { + _RETURN(*p_a._data._basis * *p_b._data._basis); + } + default: + _RETURN_FAIL; + } + } + + CASE_TYPE(math, OP_MULTIPLY, TRANSFORM) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(p_a._data._transform->xform(*(const Vector3 *)p_b._data._mem)); + } + case VECTOR3I: { + _RETURN(p_a._data._transform->xform(*(const Vector3i *)p_b._data._mem)); + } + case TRANSFORM: { + _RETURN(*p_a._data._transform * *p_b._data._transform); + } + default: + _RETURN_FAIL; + } + } + + 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)); + } + case VECTOR2I: { + _RETURN(p_a._data._transform2d->xform(*(const Vector2i *)p_b._data._mem)); + } + default: + _RETURN_FAIL; + } + } + + CASE_TYPE(math, OP_MULTIPLY, PROJECTION) { + switch (p_b.type) { + case VECTOR4: { + _RETURN(p_a._data._projection->xform(*(const Vector4 *)p_b._data._mem)); + } + case VECTOR3: { + _RETURN(p_a._data._projection->xform(*(const Vector3 *)p_b._data._mem)); + } + case PLANE: { + _RETURN(p_a._data._projection->xform(*(const Plane *)p_b._data._mem)); + } + case PROJECTION: { + _RETURN(p_a._data._projection->operator*(*(const Projection *)p_b._data._mem)); + } + default: + _RETURN_FAIL; + } + } + 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, VECTOR2I, *, Vector2i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3, *, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3I, *, Vector3i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR4, *, Vector4); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR4I, *, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_MULTIPLY, PLANE) + CASE_TYPE(math, OP_MULTIPLY, AABB) CASE_TYPE(math, OP_MULTIPLY, OBJECT) CASE_TYPE(math, OP_MULTIPLY, STRING_NAME) CASE_TYPE(math, OP_MULTIPLY, DICTIONARY) @@ -17957,21 +24519,50 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR4I_ARRAY); CASE_TYPE(math, OP_MULTIPLY, POOL_COLOR_ARRAY); _RETURN_FAIL; } SWITCH_OP(math, OP_DIVIDE, p_a.type) { + CASE_TYPE(math, OP_DIVIDE, QUATERNION) { + if (p_b.type != REAL) + _RETURN_FAIL; +#ifdef DEBUG_ENABLED + if (p_b._data._real == 0) { + r_valid = false; + _RETURN("Division By Zero"); + } +#endif + _RETURN(*reinterpret_cast(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, VECTOR2I, /, Vector2i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3, /, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3I, /, Vector3i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR4, /, Vector4); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR4I, /, Vector4i); 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, RECT2I) + CASE_TYPE(math, OP_DIVIDE, PLANE) + CASE_TYPE(math, OP_DIVIDE, AABB) + CASE_TYPE(math, OP_DIVIDE, BASIS) + CASE_TYPE(math, OP_DIVIDE, TRANSFORM) + CASE_TYPE(math, OP_DIVIDE, TRANSFORM2D) + CASE_TYPE(math, OP_DIVIDE, PROJECTION) CASE_TYPE(math, OP_DIVIDE, OBJECT) CASE_TYPE(math, OP_DIVIDE, STRING_NAME) CASE_TYPE(math, OP_DIVIDE, DICTIONARY) @@ -17980,7 +24571,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR4I_ARRAY); CASE_TYPE(math, OP_DIVIDE, POOL_COLOR_ARRAY); _RETURN_FAIL; } @@ -17988,12 +24584,25 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2, Vector2); DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2I, Vector2i); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3I, Vector3i); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR4, Vector4); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR4I, Vector4i); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, PLANE, Plane); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, QUATERNION, Quaternion); 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, RECT2I) + CASE_TYPE(math, OP_POSITIVE, AABB) + CASE_TYPE(math, OP_POSITIVE, BASIS) + CASE_TYPE(math, OP_POSITIVE, TRANSFORM) + CASE_TYPE(math, OP_POSITIVE, TRANSFORM2D) + CASE_TYPE(math, OP_POSITIVE, PROJECTION) CASE_TYPE(math, OP_POSITIVE, COLOR) CASE_TYPE(math, OP_POSITIVE, OBJECT) CASE_TYPE(math, OP_POSITIVE, STRING_NAME) @@ -18003,7 +24612,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR3I_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR4_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR4I_ARRAY) CASE_TYPE(math, OP_POSITIVE, POOL_COLOR_ARRAY) _RETURN_FAIL; } @@ -18012,13 +24626,26 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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, VECTOR2I, Vector2i); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3I, Vector3i); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR4, Vector4); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR4I, Vector4i); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, PLANE, Plane); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, QUATERNION, Quaternion); 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, RECT2I) + CASE_TYPE(math, OP_NEGATE, AABB) + CASE_TYPE(math, OP_NEGATE, BASIS) + CASE_TYPE(math, OP_NEGATE, TRANSFORM) + CASE_TYPE(math, OP_NEGATE, TRANSFORM2D) + CASE_TYPE(math, OP_NEGATE, PROJECTION) CASE_TYPE(math, OP_NEGATE, OBJECT) CASE_TYPE(math, OP_NEGATE, STRING_NAME) CASE_TYPE(math, OP_NEGATE, DICTIONARY) @@ -18027,7 +24654,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR3I_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR4_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR4I_ARRAY) CASE_TYPE(math, OP_NEGATE, POOL_COLOR_ARRAY) _RETURN_FAIL; } @@ -18067,8 +24699,21 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MODULE, NIL) CASE_TYPE(math, OP_MODULE, BOOL) CASE_TYPE(math, OP_MODULE, REAL) + CASE_TYPE(math, OP_MODULE, RECT2) CASE_TYPE(math, OP_MODULE, RECT2I) + CASE_TYPE(math, OP_MODULE, VECTOR2) CASE_TYPE(math, OP_MODULE, VECTOR2I) + CASE_TYPE(math, OP_MODULE, VECTOR3) + CASE_TYPE(math, OP_MODULE, VECTOR3I) + CASE_TYPE(math, OP_MODULE, VECTOR4) + CASE_TYPE(math, OP_MODULE, VECTOR4I) + CASE_TYPE(math, OP_MODULE, PLANE) + CASE_TYPE(math, OP_MODULE, QUATERNION) + CASE_TYPE(math, OP_MODULE, AABB) + CASE_TYPE(math, OP_MODULE, BASIS) + CASE_TYPE(math, OP_MODULE, TRANSFORM) + CASE_TYPE(math, OP_MODULE, TRANSFORM2D) + CASE_TYPE(math, OP_MODULE, PROJECTION) CASE_TYPE(math, OP_MODULE, COLOR) CASE_TYPE(math, OP_MODULE, OBJECT) CASE_TYPE(math, OP_MODULE, STRING_NAME) @@ -18078,7 +24723,12 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, 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_VECTOR2I_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR3I_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR4_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR4I_ARRAY) CASE_TYPE(math, OP_MODULE, POOL_COLOR_ARRAY) _RETURN_FAIL; } @@ -18201,8 +24851,50 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, void Variant::set_named(const StringName &p_index, const Variant &p_value, bool *r_valid) { bool valid = false; switch (type) { + case RECT2: { + if (p_value.type == Variant::VECTOR2) { + Rect2 *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } else if (p_value.type == Variant::VECTOR2I) { + Rect2 *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } + } break; case RECT2I: { - if (p_value.type == Variant::VECTOR2I) { + if (p_value.type == Variant::VECTOR2) { + Rect2i *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } else if (p_value.type == Variant::VECTOR2I) { Rect2i *v = reinterpret_cast(_data._mem); //scalar name if (p_index == CoreStringNames::singleton->position) { @@ -18217,6 +24909,28 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool } } } break; + case VECTOR2: { + if (p_value.type == Variant::INT) { + Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } + } + + } break; case VECTOR2I: { if (p_value.type == Variant::INT) { Vector2i *v = reinterpret_cast(_data._mem); @@ -18238,6 +24952,323 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool } } + } break; + case VECTOR3: { + if (p_value.type == Variant::INT) { + Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR3I: { + if (p_value.type == Variant::INT) { + Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR4: { + if (p_value.type == Variant::INT) { + Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR4I: { + if (p_value.type == Variant::INT) { + Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._real; + valid = true; + } + } + + } break; + case PLANE: { + if (p_value.type == Variant::INT) { + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->normal.x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->normal.y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->normal.z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->d) { + v->d = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->normal.x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->normal.y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->normal.z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->d) { + v->d = p_value._data._real; + valid = true; + } + + } else if (p_value.type == Variant::VECTOR3) { + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->normal) { + v->normal = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } + + } break; + case QUATERNION: { + if (p_value.type == Variant::INT) { + Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._real; + valid = true; + } + } + + } break; // 10 + case AABB: { + if (p_value.type == Variant::VECTOR3) { + ::AABB *v = _data._aabb; + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } else if (p_value.type == Variant::VECTOR3I) { + ::AABB *v = _data._aabb; + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = Vector3(*reinterpret_cast(p_value._data._mem)) - v->position; + valid = true; + } + } + } break; + case BASIS: { + if (p_value.type == Variant::VECTOR3) { + Basis *v = _data._basis; + //scalar name + if (p_index == CoreStringNames::singleton->x) { + v->set_axis(0, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->set_axis(1, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->set_axis(2, *reinterpret_cast(p_value._data._mem)); + valid = true; + } + } else if (p_value.type == Variant::VECTOR3I) { + Basis *v = _data._basis; + //scalar name + if (p_index == CoreStringNames::singleton->x) { + v->set_axis(0, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->set_axis(1, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->set_axis(2, *reinterpret_cast(p_value._data._mem)); + valid = true; + } + } + } break; + case TRANSFORM: { + if (p_value.type == Variant::BASIS && p_index == CoreStringNames::singleton->basis) { + _data._transform->basis = *p_value._data._basis; + valid = true; + } else if (p_value.type == Variant::VECTOR3 && p_index == CoreStringNames::singleton->origin) { + _data._transform->origin = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_value.type == Variant::VECTOR3I && p_index == CoreStringNames::singleton->origin) { + _data._transform->origin = *reinterpret_cast(p_value._data._mem); + valid = true; + } + + } break; + case TRANSFORM2D: { + if (p_value.type == Variant::VECTOR2) { + Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + v->columns[0] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->columns[1] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->origin) { + v->columns[2] = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } else if (p_value.type == Variant::VECTOR2I) { + Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + v->columns[0] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->columns[1] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->origin) { + v->columns[2] = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } + + } break; + case PROJECTION: { + if (p_value.type == Variant::VECTOR4) { + Projection *v = _data._projection; + if (p_index == CoreStringNames::singleton->x) { + v->matrix[0] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->matrix[1] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->matrix[2] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->matrix[3] = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } + } break; case COLOR: { if (p_value.type == Variant::INT) { @@ -18342,6 +25373,17 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { *r_valid = true; } switch (type) { + case RECT2: { + const Rect2 *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + return v->size + v->position; + } + } break; case RECT2I: { const Rect2i *v = reinterpret_cast(_data._mem); //scalar name @@ -18353,6 +25395,15 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { return v->size + v->position; } } break; + case VECTOR2: { + const Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } + + } break; case VECTOR2I: { const Vector2i *v = reinterpret_cast(_data._mem); if (p_index == CoreStringNames::singleton->x) { @@ -18361,6 +25412,137 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { return v->y; } + } break; + case VECTOR3: { + const Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } + + } break; + case VECTOR3I: { + const Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } + + } break; + case VECTOR4: { + const Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + return v->w; + } + + } break; + case VECTOR4I: { + const Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + return v->w; + } + + } break; + case PLANE: { + const Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->normal.x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->normal.y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->normal.z; + } else if (p_index == CoreStringNames::singleton->d) { + return v->d; + } else if (p_index == CoreStringNames::singleton->normal) { + return v->normal; + } + + } break; + case QUATERNION: { + const Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + return v->w; + } + + } break; // 10 + case AABB: { + const ::AABB *v = _data._aabb; + //scalar name + if (p_index == CoreStringNames::singleton->position) { + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + return v->size + v->position; + } + } break; + case BASIS: { + const Basis *v = _data._basis; + //scalar name + if (p_index == CoreStringNames::singleton->x) { + return v->get_axis(0); + } else if (p_index == CoreStringNames::singleton->y) { + return v->get_axis(1); + } else if (p_index == CoreStringNames::singleton->z) { + return v->get_axis(2); + } + + } break; + case TRANSFORM: { + if (p_index == CoreStringNames::singleton->basis) { + return _data._transform->basis; + } else if (p_index == CoreStringNames::singleton->origin) { + return _data._transform->origin; + } + + } break; + case TRANSFORM2D: { + const Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + return v->columns[0]; + } else if (p_index == CoreStringNames::singleton->y) { + return v->columns[1]; + } else if (p_index == CoreStringNames::singleton->origin) { + return v->columns[2]; + } + + } break; + case PROJECTION: { + const Projection *v = _data._projection; + if (p_index == CoreStringNames::singleton->x) { + return v->matrix[0]; + } else if (p_index == CoreStringNames::singleton->y) { + return v->matrix[1]; + } else if (p_index == CoreStringNames::singleton->z) { + return v->matrix[2]; + } else if (p_index == CoreStringNames::singleton->w) { + return v->matrix[3]; + } + } break; case COLOR: { const Color *v = reinterpret_cast(_data._mem); @@ -18511,8 +25693,50 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } break; + case RECT2: { + if (p_value.type == Variant::VECTOR2 || p_value.type == Variant::VECTOR2I) { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + Rect2 *v = reinterpret_cast(_data._mem); + if (*str == "position") { + valid = true; + v->position = p_value; + return; + } else if (*str == "size") { + valid = true; + v->size = p_value; + return; + } else if (*str == "end") { + valid = true; + v->size = Vector2(p_value) - v->position; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Rect2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->position) { + valid = true; + v->position = p_value; + return; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + v->size = p_value; + return; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + v->size = Vector2(p_value) - v->position; + return; + } + } + } else { + return; + } + } break; //7 case RECT2I: { - if (p_value.type == Variant::VECTOR2I) { + if (p_value.type == Variant::VECTOR2 || p_value.type == Variant::VECTOR2I) { if (p_index.get_type() == Variant::STRING) { //scalar name @@ -18529,7 +25753,7 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } else if (*str == "end") { valid = true; //TODO fix - v->size = Vector2i(p_value) - v->position; + v->size = Vector2i(Vector2(p_value)) - v->position; return; } } else if (p_index.get_type() == Variant::STRING_NAME) { @@ -18546,7 +25770,7 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } else if (p_index == CoreStringNames::singleton->end) { valid = true; - v->size = Vector2i(p_value) - v->position; + v->size = Vector2(p_value) - v->position; return; } } @@ -18554,6 +25778,53 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } } break; + case VECTOR2: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + + if (idx < 0) { + idx += 2; + } + if (idx >= 0 && idx < 2) { + Vector2 *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + Vector2 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } + } + } break; // 5 case VECTOR2I: { if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { return; @@ -18602,6 +25873,654 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) } } break; //6 + + case VECTOR3: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + Vector3 *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector3 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } + } + + } break; + case VECTOR3I: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + Vector3i *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector3 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } + } + + } break; + case VECTOR4: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + Vector4 *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector4 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } else if (*str == "w") { + valid = true; + v->w = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->w = p_value; + return; + } + } + } break; + case VECTOR4I: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + Vector4i *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector4 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } else if (*str == "w") { + valid = true; + v->w = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->w = p_value; + return; + } + } + + } break; + case PLANE: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Plane *v = reinterpret_cast(_data._mem); + if (*str == "x") { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.x = p_value; + return; + } else if (*str == "y") { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.y = p_value; + return; + } else if (*str == "z") { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.z = p_value; + return; + } else if (*str == "normal") { + if (p_value.type != Variant::VECTOR3) { + return; + } + + valid = true; + v->normal = p_value; + return; + } else if (*str == "d") { + valid = true; + v->d = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->normal) { + if (p_value.type != Variant::VECTOR3) { + return; + } + + valid = true; + v->normal = p_value; + return; + } else if (p_index == CoreStringNames::singleton->d) { + valid = true; + v->d = p_value; + return; + } + } + + } break; + case QUATERNION: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + Quaternion *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } else if (*str == "w") { + valid = true; + v->w = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->w = p_value; + return; + } + } + + } break; // 10 + case AABB: { + if (p_value.type != Variant::VECTOR3) { + return; + } + + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + ::AABB *v = _data._aabb; + if (*str == "position") { + valid = true; + v->position = p_value; + return; + } else if (*str == "size") { + valid = true; + v->size = p_value; + return; + } else if (*str == "end") { + valid = true; + v->size = Vector3(p_value) - v->position; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + ::AABB *v = _data._aabb; + if (p_index == CoreStringNames::singleton->position) { + valid = true; + v->position = p_value; + return; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + v->size = p_value; + return; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + v->size = Vector3(p_value) - v->position; + return; + } + } + } break; + case BASIS: { + if (p_value.type != Variant::VECTOR3) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + Basis *v = _data._basis; + + valid = true; + v->set_axis(index, p_value); + return; + } + } else if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + Basis *v = _data._basis; + + if (*str == "x") { + valid = true; + v->set_axis(0, p_value); + return; + } else if (*str == "y") { + valid = true; + v->set_axis(1, p_value); + return; + } else if (*str == "z") { + valid = true; + v->set_axis(2, p_value); + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Basis *v = _data._basis; + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->set_axis(0, p_value); + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->set_axis(1, p_value); + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->set_axis(2, p_value); + return; + } + } + + } break; + case TRANSFORM: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + if (p_value.type != Variant::VECTOR3) { + return; + } + + int index = p_index; + + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + Transform *v = _data._transform; + valid = true; + if (index == 3) { + v->origin = p_value; + } else { + v->basis.set_axis(index, p_value); + } + return; + } + } else if (p_index.get_type() == Variant::STRING) { + Transform *v = _data._transform; + const String *str = reinterpret_cast(p_index._data._mem); + + if (*str == "basis") { + if (p_value.type != Variant::BASIS) { + return; + } + valid = true; + v->basis = p_value; + return; + } + if (*str == "origin") { + if (p_value.type != Variant::VECTOR3) { + return; + } + valid = true; + v->origin = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Transform *v = _data._transform; + + if (p_index == CoreStringNames::singleton->basis) { + if (p_value.type != Variant::BASIS) { + return; + } + valid = true; + v->basis = p_value; + return; + } + if (p_index == CoreStringNames::singleton->origin) { + if (p_value.type != Variant::VECTOR3) { + return; + } + valid = true; + v->origin = p_value; + return; + } + } + + } break; + case TRANSFORM2D: { + if (p_value.type != Variant::VECTOR2 || p_value.get_type() != Variant::VECTOR2I) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + Transform2D *v = _data._transform2d; + + valid = true; + v->columns[index] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Transform2D *v = _data._transform2d; + if (*str == "x") { + valid = true; + v->columns[0] = p_value; + return; + } else if (*str == "y") { + valid = true; + v->columns[1] = p_value; + return; + } else if (*str == "origin") { + valid = true; + v->columns[2] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->columns[0] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->columns[1] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->origin) { + valid = true; + v->columns[2] = p_value; + return; + } + } + + } break; + case PROJECTION: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + if (p_value.type != Variant::VECTOR4) { + return; + } + + int index = p_index; + + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + Projection *v = _data._projection; + valid = true; + v->matrix[index] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + Projection *v = _data._projection; + const String *str = reinterpret_cast(p_index._data._mem); + + if (p_value.type != Variant::VECTOR4) { + return; + } + + if (*str == "x") { + valid = true; + v->matrix[0] = p_value; + return; + } else if (*str == "y") { + valid = true; + v->matrix[1] = p_value; + return; + } else if (*str == "z") { + valid = true; + v->matrix[2] = p_value; + return; + } else if (*str == "w") { + valid = true; + v->matrix[3] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Projection *v = _data._projection; + + if (p_value.type != Variant::VECTOR4) { + return; + } + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->matrix[0] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->matrix[1] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->matrix[2] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->matrix[3] = p_value; + return; + } + } + + } break; case COLOR: { if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { return; @@ -18747,7 +26666,12 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) DEFAULT_OP_DVECTOR_SET(POOL_INT_ARRAY, int, p_value.type != Variant::REAL && p_value.type != Variant::INT) DEFAULT_OP_DVECTOR_SET(POOL_REAL_ARRAY, real_t, p_value.type != Variant::REAL && p_value.type != Variant::INT) DEFAULT_OP_DVECTOR_SET(POOL_STRING_ARRAY, String, p_value.type != Variant::STRING) - DEFAULT_OP_DVECTOR_SET(POOL_VECTOR2I_ARRAY, Vector2i, p_value.type != Variant::VECTOR2I) // 25 + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR2_ARRAY, Vector2, p_value.type != Variant::VECTOR2) // 25 + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR2I_ARRAY, Vector2i, p_value.type != Variant::VECTOR2I) + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR3_ARRAY, Vector3, p_value.type != Variant::VECTOR3) + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR3I_ARRAY, Vector3i, p_value.type != Variant::VECTOR3I) + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR4_ARRAY, Vector4, p_value.type != Variant::VECTOR4) + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR4I_ARRAY, Vector4i, p_value.type != Variant::VECTOR4I) DEFAULT_OP_DVECTOR_SET(POOL_COLOR_ARRAY, Color, p_value.type != Variant::COLOR) default: return; @@ -18790,6 +26714,38 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } break; + case RECT2: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const Rect2 *v = reinterpret_cast(_data._mem); + if (*str == "position") { + valid = true; + return v->position; + } else if (*str == "size") { + valid = true; + return v->size; + } else if (*str == "end") { + valid = true; + return v->size + v->position; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Rect2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->position) { + valid = true; + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + return v->size + v->position; + } + } + } break; case RECT2I: { if (p_index.get_type() == Variant::STRING) { //scalar name @@ -18822,6 +26778,44 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } } break; + case VECTOR2: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + if (idx < 0) { + idx += 2; + } + if (idx >= 0 && idx < 2) { + const Vector2 *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const Vector2 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } + } + + } break; // 5 case VECTOR2I: { if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { // scalar index @@ -18860,6 +26854,470 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } break; // 6 + case VECTOR3: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + const Vector3 *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector3 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } + } + + } break; + case VECTOR3I: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + const Vector3i *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector3i *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } + } + + } break; + case VECTOR4: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + const Vector4 *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector4 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } else if (*str == "w") { + valid = true; + return v->w; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->w; + } + } + + } break; + case VECTOR4I: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + const Vector4i *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector4i *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } else if (*str == "w") { + valid = true; + return v->w; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + const Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->w; + } + } + + } break; + case PLANE: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Plane *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->normal.x; + } else if (*str == "y") { + valid = true; + return v->normal.y; + } else if (*str == "z") { + valid = true; + return v->normal.z; + } else if (*str == "normal") { + valid = true; + return v->normal; + } else if (*str == "d") { + valid = true; + return v->d; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->normal.x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->normal.y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->normal.z; + } else if (p_index == CoreStringNames::singleton->normal) { + valid = true; + return v->normal; + } else if (p_index == CoreStringNames::singleton->d) { + valid = true; + return v->d; + } + } + + } break; + case QUATERNION: { + if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + const Quaternion *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } else if (*str == "w") { + valid = true; + return v->w; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->w; + } + } + + } break; // 10 + case AABB: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const ::AABB *v = _data._aabb; + if (*str == "position") { + valid = true; + return v->position; + } else if (*str == "size") { + valid = true; + return v->size; + } else if (*str == "end") { + valid = true; + return v->size + v->position; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const ::AABB *v = _data._aabb; + if (p_index == CoreStringNames::singleton->position) { + valid = true; + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + return v->size + v->position; + } + } + } break; + case BASIS: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + const Basis *v = _data._basis; + + valid = true; + return v->get_axis(index); + } + } else if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + const Basis *v = _data._basis; + + if (*str == "x") { + valid = true; + return v->get_axis(0); + } else if (*str == "y") { + valid = true; + return v->get_axis(1); + } else if (*str == "z") { + valid = true; + return v->get_axis(2); + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Basis *v = _data._basis; + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->get_axis(0); + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->get_axis(1); + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->get_axis(2); + } + } + + } break; + case TRANSFORM: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + const Transform *v = _data._transform; + valid = true; + return index == 3 ? v->origin : v->basis.get_axis(index); + } + } else if (p_index.get_type() == Variant::STRING) { + const Transform *v = _data._transform; + const String *str = reinterpret_cast(p_index._data._mem); + + if (*str == "basis") { + valid = true; + return v->basis; + } + if (*str == "origin") { + valid = true; + return v->origin; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Transform *v = _data._transform; + + if (p_index == CoreStringNames::singleton->basis) { + valid = true; + return v->basis; + } + if (p_index == CoreStringNames::singleton->origin) { + valid = true; + return v->origin; + } + } + + } break; + case TRANSFORM2D: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + const Transform2D *v = _data._transform2d; + + valid = true; + return v->columns[index]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Transform2D *v = _data._transform2d; + if (*str == "x") { + valid = true; + return v->columns[0]; + } else if (*str == "y") { + valid = true; + return v->columns[1]; + } else if (*str == "origin") { + valid = true; + return v->columns[2]; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->columns[0]; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->columns[1]; + } else if (p_index == CoreStringNames::singleton->origin) { + valid = true; + return v->columns[2]; + } + } + + } break; + case PROJECTION: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + const Projection *v = _data._projection; + valid = true; + return v->matrix[index]; + } + } else if (p_index.get_type() == Variant::STRING) { + const Projection *v = _data._projection; + const String *str = reinterpret_cast(p_index._data._mem); + + if (*str == "x") { + valid = true; + return v->matrix[0]; + } else if (*str == "y") { + valid = true; + return v->matrix[1]; + } else if (*str == "z") { + valid = true; + return v->matrix[2]; + } else if (*str == "w") { + valid = true; + return v->matrix[3]; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Projection *v = _data._projection; + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->matrix[0]; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->matrix[1]; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->matrix[2]; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->matrix[3]; + } + } + + } break; case COLOR: { if (p_index.get_type() == Variant::STRING) { const String *str = reinterpret_cast(p_index._data._mem); @@ -18977,7 +27435,12 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { DEFAULT_OP_DVECTOR_GET(POOL_INT_ARRAY, int) DEFAULT_OP_DVECTOR_GET(POOL_REAL_ARRAY, real_t) DEFAULT_OP_DVECTOR_GET(POOL_STRING_ARRAY, String) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR2_ARRAY, Vector2) DEFAULT_OP_DVECTOR_GET(POOL_VECTOR2I_ARRAY, Vector2i) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR3_ARRAY, Vector3) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR3I_ARRAY, Vector3i) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR4_ARRAY, Vector4) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR4I_ARRAY, Vector4i) DEFAULT_OP_DVECTOR_GET(POOL_COLOR_ARRAY, Color) default: return Variant(); @@ -19111,6 +27574,25 @@ bool Variant::in(const Variant &p_index, bool *r_valid) const { } } break; //25 + case POOL_VECTOR2_ARRAY: { + if (p_index.get_type() == Variant::VECTOR2) { + Vector2 index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; case POOL_VECTOR2I_ARRAY: { if (p_index.get_type() == Variant::VECTOR2I) { Vector2i index = p_index; @@ -19129,6 +27611,82 @@ bool Variant::in(const Variant &p_index, bool *r_valid) const { return false; } + } break; + case POOL_VECTOR3_ARRAY: { + if (p_index.get_type() == Variant::VECTOR3) { + Vector3 index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR3I_ARRAY: { + if (p_index.get_type() == Variant::VECTOR3I) { + Vector3i index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR4_ARRAY: { + if (p_index.get_type() == Variant::VECTOR4) { + Vector4 index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR4I_ARRAY: { + if (p_index.get_type() == Variant::VECTOR4I) { + Vector4i index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + } break; case POOL_COLOR_ARRAY: { if (p_index.get_type() == Variant::COLOR) { @@ -19169,6 +27727,14 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { r_iter = 0; return _data._real > 0.0; } break; + case VECTOR2: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + + r_iter = from; + + return from < to; + } break; case VECTOR2I: { int64_t from = reinterpret_cast(_data._mem)->x; int64_t to = reinterpret_cast(_data._mem)->y; @@ -19177,6 +27743,38 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { return from < to; } break; + case VECTOR3: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + r_iter = from; + + if (from == to) { + return false; + } else if (from < to) { + return step > 0; + } else { + return step < 0; + } + //return true; + } break; + case VECTOR3I: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + r_iter = from; + + if (from == to) { + return false; + } else if (from < to) { + return step > 0; + } else { + return step < 0; + } + //return true; + } break; case STRING: { const String *str = reinterpret_cast(_data._mem); if (str->empty()) { @@ -19239,6 +27837,14 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { r_iter = 0; return true; } break; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; case POOL_VECTOR2I_ARRAY: { const PoolVector *arr = reinterpret_cast *>(_data._mem); if (arr->size() == 0) { @@ -19247,6 +27853,38 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { r_iter = 0; return true; } break; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; case POOL_COLOR_ARRAY: { const PoolVector *arr = reinterpret_cast *>(_data._mem); if (arr->size() == 0) { @@ -19284,6 +27922,19 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { r_iter = idx; return true; } break; + case VECTOR2: { + int64_t to = reinterpret_cast(_data._mem)->y; + + int64_t idx = r_iter; + idx++; + + if (idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; case VECTOR2I: { int64_t to = reinterpret_cast(_data._mem)->y; @@ -19297,6 +27948,42 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { r_iter = idx; return true; } break; + case VECTOR3: { + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + int64_t idx = r_iter; + idx += step; + + if (step < 0 && idx <= to) { + return false; + } + + if (step > 0 && idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; + case VECTOR3I: { + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + int64_t idx = r_iter; + idx += step; + + if (step < 0 && idx <= to) { + return false; + } + + if (step > 0 && idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; case STRING: { const String *str = reinterpret_cast(_data._mem); int idx = r_iter; @@ -19371,6 +28058,16 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { r_iter = idx; return true; } break; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; case POOL_VECTOR2I_ARRAY: { const PoolVector *arr = reinterpret_cast *>(_data._mem); int idx = r_iter; @@ -19381,6 +28078,46 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { r_iter = idx; return true; } break; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; case POOL_COLOR_ARRAY: { const PoolVector *arr = reinterpret_cast *>(_data._mem); int idx = r_iter; @@ -19408,9 +28145,18 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { case REAL: { return r_iter; } break; + case VECTOR2: { + return r_iter; + } break; case VECTOR2I: { return r_iter; } break; + case VECTOR3: { + return r_iter; + } break; + case VECTOR3I: { + return r_iter; + } break; case STRING: { const String *str = reinterpret_cast(_data._mem); return str->substr(r_iter, 1); @@ -19471,6 +28217,17 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { r_valid = false; return Variant(); } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } #endif return arr->get(idx); } break; @@ -19482,6 +28239,50 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { r_valid = false; return Variant(); } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } #endif return arr->get(idx); } break; @@ -19548,6 +28349,12 @@ void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) { r_dst = ra - rb; } return; + case RECT2: { + const Rect2 *ra = reinterpret_cast(a._data._mem); + const Rect2 *rb = reinterpret_cast(b._data._mem); + r_dst = Rect2(ra->position - rb->position, ra->size - rb->size); + } + return; case RECT2I: { const Rect2i *ra = reinterpret_cast(a._data._mem); const Rect2i *rb = reinterpret_cast(b._data._mem); @@ -19564,6 +28371,10 @@ void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) { r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy)); } return; + case VECTOR2: { + r_dst = *reinterpret_cast(a._data._mem) - *reinterpret_cast(b._data._mem); + } + return; case VECTOR2I: { int32_t vax = reinterpret_cast(a._data._mem)->x; int32_t vbx = reinterpret_cast(b._data._mem)->x; @@ -19572,6 +28383,49 @@ void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) { r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby)); } return; + case VECTOR3: { + r_dst = *reinterpret_cast(a._data._mem) - *reinterpret_cast(b._data._mem); + } + return; + case VECTOR3I: { + int32_t vax = reinterpret_cast(a._data._mem)->x; + int32_t vbx = reinterpret_cast(b._data._mem)->x; + int32_t vay = reinterpret_cast(a._data._mem)->y; + int32_t vby = reinterpret_cast(b._data._mem)->y; + int32_t vaz = reinterpret_cast(a._data._mem)->z; + int32_t vbz = reinterpret_cast(b._data._mem)->z; + r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz)); + } + return; + case VECTOR4: { + r_dst = *reinterpret_cast(a._data._mem) - *reinterpret_cast(b._data._mem); + } + return; + case VECTOR4I: { + int32_t vax = reinterpret_cast(a._data._mem)->x; + int32_t vbx = reinterpret_cast(b._data._mem)->x; + int32_t vay = reinterpret_cast(a._data._mem)->y; + int32_t vaw = reinterpret_cast(a._data._mem)->w; + int32_t vby = reinterpret_cast(b._data._mem)->y; + int32_t vaz = reinterpret_cast(a._data._mem)->z; + int32_t vbz = reinterpret_cast(b._data._mem)->z; + int32_t vbw = reinterpret_cast(b._data._mem)->w; + r_dst = Vector4i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz), int32_t(vaw - vbw)); + } + return; + case AABB: { + const ::AABB *ra = reinterpret_cast(a._data._mem); + const ::AABB *rb = reinterpret_cast(b._data._mem); + r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size); + } + return; + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast(a._data._mem); + const Quaternion *qb = reinterpret_cast(b._data._mem); + r_dst = (*qb).inverse() * *qa; + } + return; case COLOR: { const Color *ca = reinterpret_cast(a._data._mem); const Color *cb = reinterpret_cast(b._data._mem); @@ -19622,16 +28476,55 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = ra + rb * c; } return; + case RECT2: { + const Rect2 *ra = reinterpret_cast(a._data._mem); + const Rect2 *rb = reinterpret_cast(b._data._mem); + r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c); + } + return; case RECT2I: { const Rect2i *ra = reinterpret_cast(a._data._mem); const Rect2i *rb = reinterpret_cast(b._data._mem); r_dst = Rect2i(ra->position + rb->position * c, ra->size + rb->size * c); } return; + case VECTOR2: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; case VECTOR2I: { r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; } return; + case VECTOR3: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR3I: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR4: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR4I: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case AABB: { + const ::AABB *ra = reinterpret_cast(a._data._mem); + const ::AABB *rb = reinterpret_cast(b._data._mem); + r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c); + } + return; + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast(a._data._mem); + const Quaternion *qb = reinterpret_cast(b._data._mem); + r_dst = *qa * empty_rot.slerp(*qb, c); + } + return; case COLOR: { const Color *ca = reinterpret_cast(a._data._mem); const Color *cb = reinterpret_cast(b._data._mem); @@ -19728,14 +28621,62 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = dst; } return; + case RECT2: { + r_dst = Rect2(reinterpret_cast(a._data._mem)->position.linear_interpolate(reinterpret_cast(b._data._mem)->position, c), reinterpret_cast(a._data._mem)->size.linear_interpolate(reinterpret_cast(b._data._mem)->size, c)); + } + return; case RECT2I: { - r_dst = Rect2i(reinterpret_cast(a._data._mem)->position.linear_interpolate(reinterpret_cast(b._data._mem)->position, c), reinterpret_cast(a._data._mem)->size.linear_interpolate(reinterpret_cast(b._data._mem)->size, c)); + r_dst = Rect2(reinterpret_cast(a._data._mem)->position.linear_interpolate(reinterpret_cast(b._data._mem)->position, c), reinterpret_cast(a._data._mem)->size.linear_interpolate(reinterpret_cast(b._data._mem)->size, c)); + } + return; + case VECTOR2: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); } return; case VECTOR2I: { r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); } return; + case VECTOR3: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR3I: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR4: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR4I: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case PLANE: { + r_dst = a; + } + return; + case QUATERNION: { + r_dst = reinterpret_cast(a._data._mem)->slerp(*reinterpret_cast(b._data._mem), c); + } + return; + case AABB: { + r_dst = ::AABB(a._data._aabb->position.linear_interpolate(b._data._aabb->position, c), a._data._aabb->size.linear_interpolate(b._data._aabb->size, c)); + } + return; + case BASIS: { + r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis; + } + return; + case TRANSFORM: { + r_dst = a._data._transform->interpolate_with(*b._data._transform, c); + } + return; + case TRANSFORM2D: { + r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c); + } + return; case COLOR: { r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); } @@ -19811,6 +28752,28 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = a; } return; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; case POOL_VECTOR2I_ARRAY: { const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); @@ -19833,6 +28796,96 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } } return; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + + r_dst = a; + } + return; case POOL_COLOR_ARRAY: { const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); diff --git a/platform/sfwl.h b/platform/sfw.h similarity index 74% rename from platform/sfwl.h rename to platform/sfw.h index 1e8e77e..3de3c5e 100644 --- a/platform/sfwl.h +++ b/platform/sfw.h @@ -1,9 +1,9 @@ -#ifndef SFWL_H -#define SFWL_H +#ifndef SFW_H +#define SFW_H -#define SFWL_VERSION 1 +#define SFW_VERSION 1 -// SFW - Simple Framework - Lite Version - https://github.com/Relintai/sfw +// SFW - Simple Framework - https://github.com/Relintai/sfw // Simple c++ app / game framework inspired by the single file c game engines // and libraries, especially [FWK](https://github.com/r-lyeh/FWK). @@ -164,7 +164,7 @@ Any contribution to this repository is implicitly subjected to the same release //=================== CORE SECTION =================== -#line 1 "sfwl/core/int_types.h" +#line 1 "sfw/core/int_types.h" /*************************************************************************/ /* int_types.h */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -199,7 +199,7 @@ typedef unsigned long long uint64_t; #endif #line 0 -#line 1 "sfwl/core/math_defs.h" +#line 1 "sfw/core/math_defs.h" /*************************************************************************/ /* math_defs.h */ @@ -297,7 +297,7 @@ typedef float real_t; #line 0 -#line 1 "sfwl/core/error_list.h" +#line 1 "sfw/core/error_list.h" /*************************************************************************/ /* error_list.h */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -364,7 +364,7 @@ enum Error { #line 0 -#line 1 "sfwl/core/logger.h" +#line 1 "sfw/core/logger.h" class String; @@ -436,7 +436,7 @@ public: #line 0 -#line 1 "sfwl/core/typedefs.h" +#line 1 "sfw/core/typedefs.h" /*************************************************************************/ /* typedefs.h */ @@ -832,7 +832,7 @@ struct _GlobalLock { #line 0 -#line 1 "sfwl/core/marshalls.h" +#line 1 "sfw/core/marshalls.h" /*************************************************************************/ /* marshalls.h */ @@ -971,7 +971,7 @@ static inline double decode_double(const uint8_t *p_arr) { #line 0 -#line 1 "sfwl/core/sfw_time.h" +#line 1 "sfw/core/sfw_time.h" // ----------------------------------------------------------------------------- // time framework utils @@ -996,7 +996,7 @@ public: #line 0 -#line 1 "sfwl/core/safe_refcount.h" +#line 1 "sfw/core/safe_refcount.h" /*************************************************************************/ /* safe_refcount.h */ @@ -1302,7 +1302,7 @@ public: #line 0 -#line 1 "sfwl/core/thread.h" +#line 1 "sfw/core/thread.h" /*************************************************************************/ /* thread.h */ @@ -1394,7 +1394,7 @@ public: #line 0 -#line 1 "sfwl/core/error_macros.h" +#line 1 "sfw/core/error_macros.h" // Based on Godot Engine's error_macros.h // MIT License @@ -1683,7 +1683,7 @@ _FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3, E #line 0 -#line 1 "sfwl/core/memory.h" +#line 1 "sfw/core/memory.h" /*************************************************************************/ /* memory.h */ @@ -1858,7 +1858,7 @@ struct _GlobalNilClass { #line 0 -#line 1 "sfwl/core/mutex.h" +#line 1 "sfw/core/mutex.h" /*************************************************************************/ /* mutex.h */ @@ -1950,7 +1950,7 @@ using BinaryMutex = MutexImpl; // Non-recursive, handle with care #line 0 -#line 1 "sfwl/core/rw_lock.h" +#line 1 "sfw/core/rw_lock.h" /*************************************************************************/ /* rw_lock.h */ @@ -2039,7 +2039,7 @@ public: #line 0 -#line 1 "sfwl/core/spin_lock.h" +#line 1 "sfw/core/spin_lock.h" /*************************************************************************/ /* spin_lock.h */ @@ -2062,7 +2062,7 @@ public: #line 0 -#line 1 "sfwl/core/thread_safe.h" +#line 1 "sfw/core/thread_safe.h" /*************************************************************************/ /* thread_safe.h */ @@ -2076,7 +2076,7 @@ public: #line 0 -#line 1 "sfwl/core/pcg.h" +#line 1 "sfw/core/pcg.h" // *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org // Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) @@ -2092,7 +2092,7 @@ uint32_t pcg32_boundedrand_r(pcg32_random_t *rng, uint32_t bound); #line 0 -#line 1 "sfwl/core/random_pcg.h" +#line 1 "sfw/core/random_pcg.h" /*************************************************************************/ /* random_pcg.h */ @@ -2202,7 +2202,7 @@ public: #line 0 -#line 1 "sfwl/core/math_funcs.h" +#line 1 "sfw/core/math_funcs.h" /*************************************************************************/ /* math_funcs.h */ @@ -2834,7 +2834,7 @@ public: #line 0 -#line 1 "sfwl/core/cowdata.h" +#line 1 "sfw/core/cowdata.h" /*************************************************************************/ /* cowdata.h */ @@ -3196,7 +3196,7 @@ CowData::~CowData() { #line 0 -#line 1 "sfwl/core/sort_array.h" +#line 1 "sfw/core/sort_array.h" /*************************************************************************/ /* sort_array.h */ @@ -3491,7 +3491,7 @@ public: #line 0 -#line 1 "sfwl/core/rb_map.h" +#line 1 "sfw/core/rb_map.h" /*************************************************************************/ /* rb_map.h */ @@ -4141,7 +4141,7 @@ public: #line 0 -#line 1 "sfwl/core/rb_set.h" +#line 1 "sfw/core/rb_set.h" /*************************************************************************/ /* rb_set.h */ @@ -4745,7 +4745,7 @@ public: #line 0 -#line 1 "sfwl/core/vmap.h" +#line 1 "sfw/core/vmap.h" /*************************************************************************/ /* vmap.h */ @@ -4920,7 +4920,7 @@ public: #line 0 -#line 1 "sfwl/core/vector.h" +#line 1 "sfw/core/vector.h" /*************************************************************************/ /* vector.h */ @@ -5087,7 +5087,7 @@ bool Vector::push_back(T p_elem) { #line 0 -#line 1 "sfwl/core/vset.h" +#line 1 "sfw/core/vset.h" /*************************************************************************/ /* vset.h */ @@ -5200,7 +5200,7 @@ public: #line 0 -#line 1 "sfwl/core/list.h" +#line 1 "sfw/core/list.h" /*************************************************************************/ /* list.h */ @@ -5871,7 +5871,7 @@ public: #line 0 -#line 1 "sfwl/core/ring_buffer.h" +#line 1 "sfw/core/ring_buffer.h" /*************************************************************************/ /* ring_buffer.h */ @@ -6066,7 +6066,7 @@ public: #line 0 -#line 1 "sfwl/core/paged_allocator.h" +#line 1 "sfw/core/paged_allocator.h" /*************************************************************************/ /* paged_allocator.h */ @@ -6170,7 +6170,7 @@ public: #line 0 -#line 1 "sfwl/core/pool_allocator.h" +#line 1 "sfw/core/pool_allocator.h" /*************************************************************************/ /* pool_allocator.h */ @@ -6293,7 +6293,7 @@ public: #line 0 -#line 1 "sfwl/core/char_range.inc" +#line 1 "sfw/core/char_range.inc" /*************************************************************************/ /* char_range.inc */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -7721,7 +7721,7 @@ static CharRange xid_continue[] = { #line 0 -#line 1 "sfwl/core/char_utils.h" +#line 1 "sfw/core/char_utils.h" /*************************************************************************/ /* char_utils.h */ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ @@ -7803,7 +7803,7 @@ static _FORCE_INLINE_ bool is_underscore(char32_t p_char) { #line 0 -#line 1 "sfwl/core/ustring.h" +#line 1 "sfw/core/ustring.h" /*************************************************************************/ /* ustring.h */ @@ -8403,7 +8403,7 @@ bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); #line 0 -#line 1 "sfwl/core/string_name.h" +#line 1 "sfw/core/string_name.h" /*************************************************************************/ /* string_name.h */ @@ -8605,601 +8605,7 @@ StringName _scs_create(const char *p_chr, bool p_static = false); #line 0 -#line 1 "sfwl/core/color.h" - -/*************************************************************************/ -/* color.h */ -/* From https://github.com/Relintai/pandemonium_engine (MIT) */ -/*************************************************************************/ - -struct _NO_DISCARD_CLASS_ Color { - union { - struct { - float r; - float g; - float b; - float a; - }; - float components[4]; - }; - - 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_rgba32() const; - uint32_t to_argb32() const; - uint32_t to_abgr32() const; - uint64_t to_rgba64() const; - uint64_t to_argb64() const; - uint64_t to_abgr64() const; - float get_h() const; - float get_s() const; - float get_v() const; - void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); - - _FORCE_INLINE_ float &operator[](int idx) { - return components[idx]; - } - _FORCE_INLINE_ const float &operator[](int idx) const { - 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); - - bool is_equal_approx(const Color &p_color) const; - - Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const; - - void invert(); - void contrast(); - Color inverted() const; - Color contrasted() const; - - _FORCE_INLINE_ float get_luminance() const { - return 0.2126 * r + 0.7152 * g + 0.0722 * b; - } - - _FORCE_INLINE_ Color linear_interpolate(const Color &p_to, float p_weight) const { - Color res = *this; - - res.r += (p_weight * (p_to.r - r)); - res.g += (p_weight * (p_to.g - g)); - res.b += (p_weight * (p_to.b - b)); - res.a += (p_weight * (p_to.a - a)); - - return res; - } - - _FORCE_INLINE_ Color darkened(float p_amount) const { - Color res = *this; - res.r = res.r * (1.0f - p_amount); - res.g = res.g * (1.0f - p_amount); - res.b = res.b * (1.0f - p_amount); - return res; - } - - _FORCE_INLINE_ Color lightened(float p_amount) const { - Color res = *this; - res.r = res.r + (1.0f - res.r) * p_amount; - res.g = res.g + (1.0f - res.g) * p_amount; - res.b = res.b + (1.0f - res.b) * p_amount; - return res; - } - - _FORCE_INLINE_ uint32_t to_rgbe9995() const { - const float pow2to9 = 512.0f; - const float B = 15.0f; - //const float Emax = 31.0f; - const float N = 9.0f; - - float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f); - - float cRed = MAX(0.0f, MIN(sharedexp, r)); - float cGreen = MAX(0.0f, MIN(sharedexp, g)); - float cBlue = MAX(0.0f, MIN(sharedexp, b)); - - float cMax = MAX(cRed, MAX(cGreen, cBlue)); - - // expp = MAX(-B - 1, log2(maxc)) + 1 + B - - float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B; - - float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); - - float exps = expp + 1.0f; - - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } - - float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - - return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27); - } - - _FORCE_INLINE_ Color blend(const Color &p_over) const { - Color res; - float sa = 1.0 - p_over.a; - res.a = a * sa + p_over.a; - if (res.a == 0) { - return Color(0, 0, 0, 0); - } else { - res.r = (r * a * sa + p_over.r * p_over.a) / res.a; - res.g = (g * a * sa + p_over.g * p_over.a) / res.a; - res.b = (b * a * sa + p_over.b * p_over.a) / res.a; - } - return res; - } - - _FORCE_INLINE_ Color to_linear() const { - return Color( - r < 0.04045 ? r * (1.0 / 12.92) : Math::pow((r + 0.055) * (1.0 / (1 + 0.055)), 2.4), - g < 0.04045 ? g * (1.0 / 12.92) : Math::pow((g + 0.055) * (1.0 / (1 + 0.055)), 2.4), - b < 0.04045 ? b * (1.0 / 12.92) : Math::pow((b + 0.055) * (1.0 / (1 + 0.055)), 2.4), - a); - } - _FORCE_INLINE_ Color to_srgb() const { - return Color( - r < 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055, - g < 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055, - b < 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a); - } - - static Color hex(uint32_t p_hex); - static Color hex64(uint64_t p_hex); - static Color html(const String &p_color); - static bool html_is_valid(const String &p_color); - String to_html(bool p_alpha = true) const; - Color from_hsv(float p_h, float p_s, float p_v, float p_a) const; - static Color from_rgbe9995(uint32_t p_rgbe); - - _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys - operator String() const; - - static _FORCE_INLINE_ Color color8(int r, int g, int b) { - return Color(static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f); - } - - static _FORCE_INLINE_ Color color8(int r, int g, int b, int a) { - return Color(static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f, static_cast(a) / 255.0f); - } - - _FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); } - _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); } - _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); } - _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); } - _FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); } - _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); } - - _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); } - _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); } - _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); } - - /** - * No construct parameters, r=0, g=0, b=0. a=255 - */ - _FORCE_INLINE_ Color() { - r = 0; - g = 0; - b = 0; - a = 1.0; - } - - /** - * RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0 - */ - _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a = 1.0) { - r = p_r; - g = p_g; - b = p_b; - a = p_a; - } - - /** - * Construct a Color from another Color, but with the specified alpha value. - */ - _FORCE_INLINE_ Color(const Color &p_c, float p_a) { - r = p_c.r; - g = p_c.g; - b = p_c.b; - a = p_a; - } -}; - -bool Color::operator<(const Color &p_color) const { - if (r == p_color.r) { - if (g == p_color.g) { - if (b == p_color.b) { - return (a < p_color.a); - } else { - return (b < p_color.b); - } - } else { - return g < p_color.g; - } - } else { - return r < p_color.r; - } -} - -#line 0 - -#line 1 "sfwl/core/vector2i.h" - -/*************************************************************************/ -/* vector2i.h */ -/* From https://github.com/Relintai/pandemonium_engine (MIT) */ -/*************************************************************************/ - -class String; - -struct _NO_DISCARD_CLASS_ Vector2i { - enum Axis { - AXIS_X, - AXIS_Y, - }; - - union { - struct { - union { - int x; - int width; - }; - union { - int y; - int height; - }; - }; - - int coord[2]; - }; - - _FORCE_INLINE_ int &operator[](int p_idx) { - DEV_ASSERT((unsigned int)p_idx < 2); - return coord[p_idx]; - } - _FORCE_INLINE_ const int &operator[](int p_idx) const { - DEV_ASSERT((unsigned int)p_idx < 2); - return coord[p_idx]; - } - - _FORCE_INLINE_ void set_all(int p_value) { - x = y = p_value; - } - - _FORCE_INLINE_ int min_axis() const { - return x < y ? 0 : 1; - } - - _FORCE_INLINE_ int max_axis() const { - return x < y ? 1 : 0; - } - - Vector2i min(const Vector2i &p_vector2i) const { - return Vector2i(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y)); - } - - Vector2i max(const Vector2i &p_vector2i) const { - return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y)); - } - - _FORCE_INLINE_ static Vector2i linear_interpolate(const Vector2i &p_a, const Vector2i &p_b, real_t p_weight); - _FORCE_INLINE_ Vector2i linear_interpolate(const Vector2i &p_to, real_t p_weight) const; - - Vector2i operator+(const Vector2i &p_v) const; - void operator+=(const Vector2i &p_v); - Vector2i operator-(const Vector2i &p_v) const; - void operator-=(const Vector2i &p_v); - Vector2i operator*(const Vector2i &p_v1) const; - - Vector2i operator*(const int &rvalue) const; - void operator*=(const int &rvalue); - - Vector2i operator/(const Vector2i &p_v1) const; - - Vector2i operator/(const int &rvalue) const; - - void operator/=(const int &rvalue); - - Vector2i operator-() const; - bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } - bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } - bool operator<=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } - bool operator>=(const Vector2i &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } - - bool operator==(const Vector2i &p_vec2) const; - bool operator!=(const Vector2i &p_vec2) const; - - int64_t length_squared() const; - double length() const; - - real_t aspect() const { return width / (real_t)height; } - Vector2i sign() const { return Vector2i(SGN(x), SGN(y)); } - Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } - Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; - - operator String() const; - - inline Vector2i(const Vector2i &p_vec2) { - x = p_vec2.x; - y = p_vec2.y; - } - inline Vector2i(int p_x, int p_y) { - x = p_x; - y = p_y; - } - inline Vector2i() { - x = 0; - y = 0; - } -}; - -Vector2i Vector2i::linear_interpolate(const Vector2i &p_a, const Vector2i &p_b, real_t p_weight) { - Vector2i res = p_a; - - res.x += (p_weight * (p_b.x - p_a.x)); - res.y += (p_weight * (p_b.y - p_a.y)); - - return res; -} - -Vector2i Vector2i::linear_interpolate(const Vector2i &p_to, real_t p_weight) const { - real_t res_x = x; - real_t res_y = y; - - res_x += (p_weight * (p_to.x - x)); - res_y += (p_weight * (p_to.y - y)); - - return Vector2i(res_x, res_y); -} - -typedef Vector2i Size2i; -typedef Vector2i Point2i; - -#line 0 - -#line 1 "sfwl/core/rect2i.h" - -/*************************************************************************/ -/* rect2i.h */ -/* From https://github.com/Relintai/pandemonium_engine (MIT) */ -/*************************************************************************/ - -struct _NO_DISCARD_CLASS_ Rect2i { - Point2i position; - Size2i size; - - const Point2i &get_position() const { return position; } - void set_position(const Point2i &p_position) { position = p_position; } - const Size2i &get_size() const { return size; } - void set_size(const Size2i &p_size) { size = p_size; } - - int get_area() const { return size.width * size.height; } - - _FORCE_INLINE_ Vector2i get_center() const { return position + (size / 2); } - - inline bool intersects(const Rect2i &p_rect) const { - if (position.x > (p_rect.position.x + p_rect.size.width)) { - return false; - } - if ((position.x + size.width) < p_rect.position.x) { - return false; - } - if (position.y > (p_rect.position.y + p_rect.size.height)) { - return false; - } - if ((position.y + size.height) < p_rect.position.y) { - return false; - } - - return true; - } - - inline bool encloses(const Rect2i &p_rect) const { - return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && - ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && - ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); - } - - _FORCE_INLINE_ bool has_no_area() const { - return (size.x <= 0 || size.y <= 0); - } - - inline Rect2i clip(const Rect2i &p_rect) const { /// return a clipped rect - - Rect2i new_rect = p_rect; - - if (!intersects(new_rect)) { - return Rect2i(); - } - - new_rect.position.x = MAX(p_rect.position.x, position.x); - new_rect.position.y = MAX(p_rect.position.y, position.y); - - Point2i p_rect_end = p_rect.position + p_rect.size; - Point2i end = position + size; - - new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x); - new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y); - - return new_rect; - } - - // Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection - inline Rect2i intersection(const Rect2i &p_rect) const { - Rect2i new_rect = p_rect; - - if (!intersects(new_rect)) { - return Rect2i(); - } - - new_rect.position.x = MAX(p_rect.position.x, position.x); - new_rect.position.y = MAX(p_rect.position.y, position.y); - - Point2i p_rect_end = p_rect.position + p_rect.size; - Point2i end = position + size; - - new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; - new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; - - return new_rect; - } - - inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect - - Rect2i new_rect; - - new_rect.position.x = MIN(p_rect.position.x, position.x); - new_rect.position.y = MIN(p_rect.position.y, position.y); - - new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); - - new_rect.size = new_rect.size - new_rect.position; //make relative again - - return new_rect; - } - - bool has_point(const Point2i &p_point) const { - if (p_point.x < position.x) { - return false; - } - if (p_point.y < position.y) { - return false; - } - - if (p_point.x >= (position.x + size.x)) { - return false; - } - if (p_point.y >= (position.y + size.y)) { - return false; - } - - return true; - } - - bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } - bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } - - Rect2i grow(int p_by) const { - Rect2i g = *this; - g.position.x -= p_by; - g.position.y -= p_by; - g.size.width += p_by * 2; - g.size.height += p_by * 2; - return g; - } - - void grow_by(int p_by) { - position.x -= p_by; - position.y -= p_by; - size.width += p_by * 2; - size.height += p_by * 2; - } - - inline Rect2i grow_margin(Margin p_margin, int p_amount) const { - Rect2i g = *this; - g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, - (MARGIN_TOP == p_margin) ? p_amount : 0, - (MARGIN_RIGHT == p_margin) ? p_amount : 0, - (MARGIN_BOTTOM == p_margin) ? p_amount : 0); - return g; - } - - inline Rect2i grow_side(Side p_side, int p_amount) const { - Rect2i g = *this; - g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0, - (SIDE_TOP == p_side) ? p_amount : 0, - (SIDE_RIGHT == p_side) ? p_amount : 0, - (SIDE_BOTTOM == p_side) ? p_amount : 0); - return g; - } - - inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const { - Rect2i g = *this; - g.position.x -= p_left; - g.position.y -= p_top; - g.size.width += p_left + p_right; - g.size.height += p_top + p_bottom; - - return g; - } - - _FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const { - Rect2i r = *this; - r.expand_to(p_vector); - return r; - } - - inline void expand_to(const Point2i &p_vector) { - Point2i begin = position; - Point2i end = position + size; - - if (p_vector.x < begin.x) { - begin.x = p_vector.x; - } - if (p_vector.y < begin.y) { - begin.y = p_vector.y; - } - - if (p_vector.x > end.x) { - end.x = p_vector.x; - } - if (p_vector.y > end.y) { - end.y = p_vector.y; - } - - position = begin; - size = end - begin; - } - - _FORCE_INLINE_ Rect2i abs() const { - return Rect2i(Point2i(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); - } - - _FORCE_INLINE_ void set_end(const Vector2i &p_end) { - size = p_end - position; - } - - _FORCE_INLINE_ Vector2i get_end() const { - return position + size; - } - - operator String() const; - - Rect2i() {} - Rect2i(int p_x, int p_y, int p_width, int p_height) : - position(Point2i(p_x, p_y)), - size(Size2i(p_width, p_height)) { - } - Rect2i(const Point2i &p_pos, const Size2i &p_size) : - position(p_pos), - size(p_size) { - } -}; - -#line 0 - -#line 1 "sfwl/core/pool_vector.h" +#line 1 "sfw/core/pool_vector.h" /*************************************************************************/ /* pool_vector.h */ @@ -9902,7 +9308,7 @@ void PoolVector::sort() { #line 0 -#line 1 "sfwl/core/tight_local_vector.h" +#line 1 "sfw/core/tight_local_vector.h" /*************************************************************************/ /* tight_local_vector.h */ @@ -10189,7 +9595,7 @@ class TightLocalVectori : public TightLocalVector { #line 0 -#line 1 "sfwl/core/local_vector.h" +#line 1 "sfw/core/local_vector.h" /*************************************************************************/ /* local_vector.h */ @@ -10480,7 +9886,4732 @@ class LocalVectori : public LocalVector { #line 0 -#line 1 "sfwl/core/hashfuncs.h" +#line 1 "sfw/core/color.h" + +/*************************************************************************/ +/* color.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Color { + union { + struct { + float r; + float g; + float b; + float a; + }; + float components[4]; + }; + + 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_rgba32() const; + uint32_t to_argb32() const; + uint32_t to_abgr32() const; + uint64_t to_rgba64() const; + uint64_t to_argb64() const; + uint64_t to_abgr64() const; + float get_h() const; + float get_s() const; + float get_v() const; + void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); + + _FORCE_INLINE_ float &operator[](int idx) { + return components[idx]; + } + _FORCE_INLINE_ const float &operator[](int idx) const { + 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); + + bool is_equal_approx(const Color &p_color) const; + + Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const; + + void invert(); + void contrast(); + Color inverted() const; + Color contrasted() const; + + _FORCE_INLINE_ float get_luminance() const { + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + + _FORCE_INLINE_ Color linear_interpolate(const Color &p_to, float p_weight) const { + Color res = *this; + + res.r += (p_weight * (p_to.r - r)); + res.g += (p_weight * (p_to.g - g)); + res.b += (p_weight * (p_to.b - b)); + res.a += (p_weight * (p_to.a - a)); + + return res; + } + + _FORCE_INLINE_ Color darkened(float p_amount) const { + Color res = *this; + res.r = res.r * (1.0f - p_amount); + res.g = res.g * (1.0f - p_amount); + res.b = res.b * (1.0f - p_amount); + return res; + } + + _FORCE_INLINE_ Color lightened(float p_amount) const { + Color res = *this; + res.r = res.r + (1.0f - res.r) * p_amount; + res.g = res.g + (1.0f - res.g) * p_amount; + res.b = res.b + (1.0f - res.b) * p_amount; + return res; + } + + _FORCE_INLINE_ uint32_t to_rgbe9995() const { + const float pow2to9 = 512.0f; + const float B = 15.0f; + //const float Emax = 31.0f; + const float N = 9.0f; + + float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f); + + float cRed = MAX(0.0f, MIN(sharedexp, r)); + float cGreen = MAX(0.0f, MIN(sharedexp, g)); + float cBlue = MAX(0.0f, MIN(sharedexp, b)); + + float cMax = MAX(cRed, MAX(cGreen, cBlue)); + + // expp = MAX(-B - 1, log2(maxc)) + 1 + B + + float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B; + + float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); + + float exps = expp + 1.0f; + + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } + + float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + + return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27); + } + + _FORCE_INLINE_ Color blend(const Color &p_over) const { + Color res; + float sa = 1.0 - p_over.a; + res.a = a * sa + p_over.a; + if (res.a == 0) { + return Color(0, 0, 0, 0); + } else { + res.r = (r * a * sa + p_over.r * p_over.a) / res.a; + res.g = (g * a * sa + p_over.g * p_over.a) / res.a; + res.b = (b * a * sa + p_over.b * p_over.a) / res.a; + } + return res; + } + + _FORCE_INLINE_ Color to_linear() const { + return Color( + r < 0.04045 ? r * (1.0 / 12.92) : Math::pow((r + 0.055) * (1.0 / (1 + 0.055)), 2.4), + g < 0.04045 ? g * (1.0 / 12.92) : Math::pow((g + 0.055) * (1.0 / (1 + 0.055)), 2.4), + b < 0.04045 ? b * (1.0 / 12.92) : Math::pow((b + 0.055) * (1.0 / (1 + 0.055)), 2.4), + a); + } + _FORCE_INLINE_ Color to_srgb() const { + return Color( + r < 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055, + g < 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055, + b < 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a); + } + + static Color hex(uint32_t p_hex); + static Color hex64(uint64_t p_hex); + static Color html(const String &p_color); + static bool html_is_valid(const String &p_color); + String to_html(bool p_alpha = true) const; + Color from_hsv(float p_h, float p_s, float p_v, float p_a) const; + static Color from_rgbe9995(uint32_t p_rgbe); + + _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys + operator String() const; + + static _FORCE_INLINE_ Color color8(int r, int g, int b) { + return Color(static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f); + } + + static _FORCE_INLINE_ Color color8(int r, int g, int b, int a) { + return Color(static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f, static_cast(a) / 255.0f); + } + + _FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); } + _FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); } + _FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); } + _FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); } + + _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); } + _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); } + _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); } + + /** + * No construct parameters, r=0, g=0, b=0. a=255 + */ + _FORCE_INLINE_ Color() { + r = 0; + g = 0; + b = 0; + a = 1.0; + } + + /** + * RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0 + */ + _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a = 1.0) { + r = p_r; + g = p_g; + b = p_b; + a = p_a; + } + + /** + * Construct a Color from another Color, but with the specified alpha value. + */ + _FORCE_INLINE_ Color(const Color &p_c, float p_a) { + r = p_c.r; + g = p_c.g; + b = p_c.b; + a = p_a; + } +}; + +bool Color::operator<(const Color &p_color) const { + if (r == p_color.r) { + if (g == p_color.g) { + if (b == p_color.b) { + return (a < p_color.a); + } else { + return (b < p_color.b); + } + } else { + return g < p_color.g; + } + } else { + return r < p_color.r; + } +} + +#line 0 + +#line 1 "sfw/core/vector2.h" + +/*************************************************************************/ +/* vector2.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +class String; + +struct _NO_DISCARD_CLASS_ Vector2 { + static const int AXIS_COUNT = 2; + + enum Axis { + AXIS_X, + AXIS_Y, + }; + + union { + struct { + union { + real_t x; + real_t width; + }; + union { + real_t y; + real_t height; + }; + }; + + real_t coord[2]; + }; + + _FORCE_INLINE_ real_t &operator[](int p_idx) { + DEV_ASSERT((unsigned int)p_idx < 2); + return coord[p_idx]; + } + _FORCE_INLINE_ const real_t &operator[](int p_idx) const { + DEV_ASSERT((unsigned int)p_idx < 2); + return coord[p_idx]; + } + + _FORCE_INLINE_ void set_all(real_t p_value) { + x = y = p_value; + } + + _FORCE_INLINE_ int min_axis() const { + return x < y ? 0 : 1; + } + + _FORCE_INLINE_ int max_axis() const { + return x < y ? 1 : 0; + } + + void normalize(); + Vector2 normalized() const; + bool is_normalized() const; + + real_t length() const; + real_t length_squared() const; + Vector2 limit_length(const real_t p_len = 1.0) const; + + Vector2 min(const Vector2 &p_vector2) const { + return Vector2(MIN(x, p_vector2.x), MIN(y, p_vector2.y)); + } + + Vector2 max(const Vector2 &p_vector2) const { + return Vector2(MAX(x, p_vector2.x), MAX(y, p_vector2.y)); + } + + real_t distance_to(const Vector2 &p_vector2) const; + real_t distance_squared_to(const Vector2 &p_vector2) const; + real_t angle_to(const Vector2 &p_vector2) const; + real_t angle_to_point(const Vector2 &p_vector2) const; + _FORCE_INLINE_ Vector2 direction_to(const Vector2 &p_to) const; + + real_t dot(const Vector2 &p_other) const; + real_t cross(const Vector2 &p_other) const; + Vector2 posmod(const real_t p_mod) const; + Vector2 posmodv(const Vector2 &p_modv) const; + Vector2 project(const Vector2 &p_to) const; + + Vector2 plane_project(real_t p_d, const Vector2 &p_vec) const; + + _FORCE_INLINE_ static Vector2 linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_weight); + _FORCE_INLINE_ Vector2 linear_interpolate(const Vector2 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, real_t p_weight) const; + _FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const; + + Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const; + + Vector2 slide(const Vector2 &p_normal) const; + Vector2 bounce(const Vector2 &p_normal) const; + Vector2 reflect(const Vector2 &p_normal) const; + + bool is_equal_approx(const Vector2 &p_v) const; + + Vector2 operator+(const Vector2 &p_v) const; + void operator+=(const Vector2 &p_v); + Vector2 operator-(const Vector2 &p_v) const; + void operator-=(const Vector2 &p_v); + Vector2 operator*(const Vector2 &p_v1) const; + + Vector2 operator*(const real_t &rvalue) const; + void operator*=(const real_t &rvalue); + void operator*=(const Vector2 &rvalue) { *this = *this * rvalue; } + + Vector2 operator/(const Vector2 &p_v1) const; + + Vector2 operator/(const real_t &rvalue) const; + + void operator/=(const real_t &rvalue); + void operator/=(const Vector2 &rvalue) { *this = *this / rvalue; } + + Vector2 operator-() const; + + bool operator==(const Vector2 &p_vec2) const; + bool operator!=(const Vector2 &p_vec2) const; + + bool operator<(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator>(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y > p_vec2.y) : (x > p_vec2.x); } + bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + + real_t angle() const; + + void set_rotation(real_t p_radians) { + x = Math::cos(p_radians); + y = Math::sin(p_radians); + } + + _FORCE_INLINE_ Vector2 abs() const { + return Vector2(Math::abs(x), Math::abs(y)); + } + + Vector2 rotated(real_t p_by) const; + _FORCE_INLINE_ Vector2 tangent() const { + return Vector2(y, -x); + } + _FORCE_INLINE_ Vector2 orthogonal() const { + return Vector2(y, -x); + } + + Vector2 sign() const; + Vector2 floor() const; + Vector2 ceil() const; + Vector2 round() const; + Vector2 snapped(const Vector2 &p_by) const; + real_t aspect() const { return width / height; } + + operator String() const; + + _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { + x = p_x; + y = p_y; + } + _FORCE_INLINE_ Vector2() { x = y = 0; } +}; + +_FORCE_INLINE_ Vector2 Vector2::plane_project(real_t p_d, const Vector2 &p_vec) const { + return p_vec - *this * (dot(p_vec) - p_d); +} + +_FORCE_INLINE_ Vector2 operator*(real_t p_scalar, const Vector2 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector2 Vector2::operator+(const Vector2 &p_v) const { + return Vector2(x + p_v.x, y + p_v.y); +} +_FORCE_INLINE_ void Vector2::operator+=(const Vector2 &p_v) { + x += p_v.x; + y += p_v.y; +} +_FORCE_INLINE_ Vector2 Vector2::operator-(const Vector2 &p_v) const { + return Vector2(x - p_v.x, y - p_v.y); +} +_FORCE_INLINE_ void Vector2::operator-=(const Vector2 &p_v) { + x -= p_v.x; + y -= p_v.y; +} + +_FORCE_INLINE_ Vector2 Vector2::operator*(const Vector2 &p_v1) const { + return Vector2(x * p_v1.x, y * p_v1.y); +}; + +_FORCE_INLINE_ Vector2 Vector2::operator*(const real_t &rvalue) const { + return Vector2(x * rvalue, y * rvalue); +}; +_FORCE_INLINE_ void Vector2::operator*=(const real_t &rvalue) { + x *= rvalue; + y *= rvalue; +}; + +_FORCE_INLINE_ Vector2 Vector2::operator/(const Vector2 &p_v1) const { + return Vector2(x / p_v1.x, y / p_v1.y); +}; + +_FORCE_INLINE_ Vector2 Vector2::operator/(const real_t &rvalue) const { + return Vector2(x / rvalue, y / rvalue); +}; + +_FORCE_INLINE_ void Vector2::operator/=(const real_t &rvalue) { + x /= rvalue; + y /= rvalue; +}; + +_FORCE_INLINE_ Vector2 Vector2::operator-() const { + return Vector2(-x, -y); +} + +_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const { + return x == p_vec2.x && y == p_vec2.y; +} +_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const { + return x != p_vec2.x || y != p_vec2.y; +} + +Vector2 Vector2::linear_interpolate(const Vector2 &p_to, real_t p_weight) const { + Vector2 res = *this; + + res.x += (p_weight * (p_to.x - x)); + res.y += (p_weight * (p_to.y - y)); + + return res; +} + +Vector2 Vector2::slerp(const Vector2 &p_to, real_t p_weight) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), Vector2(), "The start Vector2 must be normalized."); +#endif + real_t theta = angle_to(p_to); + return rotated(theta * p_weight); +} + +Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const { + Vector2 res = *this; + + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - p_t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = p_t * p_t; + real_t t3 = t2 * p_t; + + return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +} + +Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const { + Vector2 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + return res; +} + +Vector2 Vector2::direction_to(const Vector2 &p_to) const { + Vector2 ret(p_to.x - x, p_to.y - y); + ret.normalize(); + return ret; +} + +Vector2 Vector2::linear_interpolate(const Vector2 &p_a, const Vector2 &p_b, real_t p_weight) { + Vector2 res = p_a; + + res.x += (p_weight * (p_b.x - p_a.x)); + res.y += (p_weight * (p_b.y - p_a.y)); + + return res; +} + +typedef Vector2 Size2; +typedef Vector2 Point2; + +#line 0 + +#line 1 "sfw/core/vector2i.h" + +/*************************************************************************/ +/* vector2i.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +class String; + +struct _NO_DISCARD_CLASS_ Vector2i { + enum Axis { + AXIS_X, + AXIS_Y, + }; + + union { + struct { + union { + int x; + int width; + }; + union { + int y; + int height; + }; + }; + + int coord[2]; + }; + + _FORCE_INLINE_ int &operator[](int p_idx) { + DEV_ASSERT((unsigned int)p_idx < 2); + return coord[p_idx]; + } + _FORCE_INLINE_ const int &operator[](int p_idx) const { + DEV_ASSERT((unsigned int)p_idx < 2); + return coord[p_idx]; + } + + _FORCE_INLINE_ void set_all(int p_value) { + x = y = p_value; + } + + _FORCE_INLINE_ int min_axis() const { + return x < y ? 0 : 1; + } + + _FORCE_INLINE_ int max_axis() const { + return x < y ? 1 : 0; + } + + Vector2i min(const Vector2i &p_vector2i) const { + return Vector2i(MIN(x, p_vector2i.x), MIN(y, p_vector2i.y)); + } + + Vector2i max(const Vector2i &p_vector2i) const { + return Vector2i(MAX(x, p_vector2i.x), MAX(y, p_vector2i.y)); + } + + _FORCE_INLINE_ static Vector2i linear_interpolate(const Vector2i &p_a, const Vector2i &p_b, real_t p_weight); + _FORCE_INLINE_ Vector2i linear_interpolate(const Vector2i &p_to, real_t p_weight) const; + + Vector2i operator+(const Vector2i &p_v) const; + void operator+=(const Vector2i &p_v); + Vector2i operator-(const Vector2i &p_v) const; + void operator-=(const Vector2i &p_v); + Vector2i operator*(const Vector2i &p_v1) const; + + Vector2i operator*(const int &rvalue) const; + void operator*=(const int &rvalue); + + Vector2i operator/(const Vector2i &p_v1) const; + + Vector2i operator/(const int &rvalue) const; + + void operator/=(const int &rvalue); + + Vector2i operator-() const; + bool operator<(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); } + bool operator>(const Vector2i &p_vec2) const { return (x == p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); } + bool operator<=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y <= p_vec2.y) : (x < p_vec2.x); } + bool operator>=(const Vector2 &p_vec2) const { return x == p_vec2.x ? (y >= p_vec2.y) : (x > p_vec2.x); } + + bool operator==(const Vector2i &p_vec2) const; + bool operator!=(const Vector2i &p_vec2) const; + + int64_t length_squared() const; + double length() const; + + real_t aspect() const { return width / (real_t)height; } + Vector2i sign() const { return Vector2i(SGN(x), SGN(y)); } + Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } + Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; + + Vector2 to_vector2() const { return Vector2(x, y); } + + operator String() const; + operator Vector2() const { return Vector2(x, y); } + + inline Vector2i(const Vector2 &p_vec2) { + x = (int)p_vec2.x; + y = (int)p_vec2.y; + } + inline Vector2i(int p_x, int p_y) { + x = p_x; + y = p_y; + } + inline Vector2i() { + x = 0; + y = 0; + } +}; + +Vector2i Vector2i::linear_interpolate(const Vector2i &p_a, const Vector2i &p_b, real_t p_weight) { + Vector2i res = p_a; + + res.x += (p_weight * (p_b.x - p_a.x)); + res.y += (p_weight * (p_b.y - p_a.y)); + + return res; +} + +Vector2i Vector2i::linear_interpolate(const Vector2i &p_to, real_t p_weight) const { + Vector2 res = *this; + + res.x += (p_weight * (p_to.x - x)); + res.y += (p_weight * (p_to.y - y)); + + return res; +} + +typedef Vector2i Size2i; +typedef Vector2i Point2i; + +#line 0 + +#line 1 "sfw/core/rect2.h" + +/*************************************************************************/ +/* rect2.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct Transform2D; +struct Rect2i; + +struct _NO_DISCARD_CLASS_ Rect2 { + Point2 position; + Size2 size; + + const Vector2 &get_position() const { return position; } + void set_position(const Vector2 &p_pos) { position = p_pos; } + const Vector2 &get_size() const { return size; } + void set_size(const Vector2 &p_size) { size = p_size; } + + real_t get_area() const { return size.width * size.height; } + + _FORCE_INLINE_ Vector2 get_center() const { return position + (size * 0.5f); } + + inline bool intersects(const Rect2 &p_rect, const bool p_include_borders = false) const { + if (p_include_borders) { + if (position.x > (p_rect.position.x + p_rect.size.width)) { + return false; + } + if ((position.x + size.width) < p_rect.position.x) { + return false; + } + if (position.y > (p_rect.position.y + p_rect.size.height)) { + return false; + } + if ((position.y + size.height) < p_rect.position.y) { + return false; + } + } else { + if (position.x >= (p_rect.position.x + p_rect.size.width)) { + return false; + } + if ((position.x + size.width) <= p_rect.position.x) { + return false; + } + if (position.y >= (p_rect.position.y + p_rect.size.height)) { + return false; + } + if ((position.y + size.height) <= p_rect.position.y) { + return false; + } + } + + return true; + } + + inline real_t distance_to(const Vector2 &p_point) const { + real_t dist = 0.0; + bool inside = true; + + if (p_point.x < position.x) { + real_t d = position.x - p_point.x; + dist = d; + inside = false; + } + if (p_point.y < position.y) { + real_t d = position.y - p_point.y; + dist = inside ? d : MIN(dist, d); + inside = false; + } + if (p_point.x >= (position.x + size.x)) { + real_t d = p_point.x - (position.x + size.x); + dist = inside ? d : MIN(dist, d); + inside = false; + } + if (p_point.y >= (position.y + size.y)) { + real_t d = p_point.y - (position.y + size.y); + dist = inside ? d : MIN(dist, d); + inside = false; + } + + if (inside) { + return 0; + } else { + return dist; + } + } + + bool intersects_transformed(const Transform2D &p_xform, const Rect2 &p_rect) const; + + bool intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos = nullptr, Point2 *r_normal = nullptr) const; + + inline bool encloses(const Rect2 &p_rect) const { + return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && + ((p_rect.position.x + p_rect.size.x) <= (position.x + size.x)) && + ((p_rect.position.y + p_rect.size.y) <= (position.y + size.y)); + } + + _FORCE_INLINE_ bool has_no_area() const { + return (size.x <= 0 || size.y <= 0); + } + inline Rect2 clip(const Rect2 &p_rect) const { /// return a clipped rect + + Rect2 new_rect = p_rect; + + if (!intersects(new_rect)) { + return Rect2(); + } + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2 p_rect_end = p_rect.position + p_rect.size; + Point2 end = position + size; + + new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; + new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + + return new_rect; + } + + inline Rect2 intersection(const Rect2 &p_rect) const { + Rect2 new_rect = p_rect; + + if (!intersects(new_rect)) { + return Rect2(); + } + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2 p_rect_end = p_rect.position + p_rect.size; + Point2 end = position + size; + + new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; + new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + + return new_rect; + } + + inline Rect2 merge(const Rect2 &p_rect) const { ///< return a merged rect + + Rect2 new_rect; + + new_rect.position.x = MIN(p_rect.position.x, position.x); + new_rect.position.y = MIN(p_rect.position.y, position.y); + + new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); + new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); + + new_rect.size = new_rect.size - new_rect.position; //make relative again + + return new_rect; + }; + inline bool has_point(const Point2 &p_point) const { + if (p_point.x < position.x) { + return false; + } + if (p_point.y < position.y) { + return false; + } + + if (p_point.x >= (position.x + size.x)) { + return false; + } + if (p_point.y >= (position.y + size.y)) { + return false; + } + + return true; + } + bool is_equal_approx(const Rect2 &p_rect) const; + + bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; } + bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; } + + inline Rect2 grow(real_t p_by) const { + Rect2 g = *this; + g.grow_by(p_by); + return g; + } + + inline void grow_by(real_t p_by) { + position.x -= p_by; + position.y -= p_by; + size.width += p_by * 2; + size.height += p_by * 2; + } + + inline Rect2 grow_margin(Margin p_margin, real_t p_amount) const { + Rect2 g = *this; + g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, + (MARGIN_TOP == p_margin) ? p_amount : 0, + (MARGIN_RIGHT == p_margin) ? p_amount : 0, + (MARGIN_BOTTOM == p_margin) ? p_amount : 0); + return g; + } + + inline Rect2 grow_side(Side p_side, real_t p_amount) const { + Rect2 g = *this; + g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0, + (SIDE_TOP == p_side) ? p_amount : 0, + (SIDE_RIGHT == p_side) ? p_amount : 0, + (SIDE_BOTTOM == p_side) ? p_amount : 0); + return g; + } + + inline Rect2 grow_individual(real_t p_left, real_t p_top, real_t p_right, real_t p_bottom) const { + Rect2 g = *this; + g.position.x -= p_left; + g.position.y -= p_top; + g.size.width += p_left + p_right; + g.size.height += p_top + p_bottom; + + return g; + } + + _FORCE_INLINE_ Rect2 expand(const Vector2 &p_vector) const { + Rect2 r = *this; + r.expand_to(p_vector); + return r; + } + + inline void expand_to(const Vector2 &p_vector) { //in place function for speed + + Vector2 begin = position; + Vector2 end = position + size; + + if (p_vector.x < begin.x) { + begin.x = p_vector.x; + } + if (p_vector.y < begin.y) { + begin.y = p_vector.y; + } + + if (p_vector.x > end.x) { + end.x = p_vector.x; + } + if (p_vector.y > end.y) { + end.y = p_vector.y; + } + + position = begin; + size = end - begin; + } + + _FORCE_INLINE_ Rect2 abs() const { + return Rect2(Point2(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); + } + + Vector2 get_support(const Vector2 &p_normal) const { + Vector2 half_extents = size * 0.5f; + Vector2 ofs = position + half_extents; + return Vector2( + (p_normal.x > 0) ? -half_extents.x : half_extents.x, + (p_normal.y > 0) ? -half_extents.y : half_extents.y) + + ofs; + } + + _FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const { + Vector2 center = get_center(); + int side_plus = 0; + int side_minus = 0; + Vector2 end = position + size; + + int i_f = p_point_count - 1; + for (int i = 0; i < p_point_count; i++) { + const Vector2 &a = p_points[i_f]; + const Vector2 &b = p_points[i]; + i_f = i; + + Vector2 r = (b - a); + float l = r.length(); + if (l == 0.0f) { + continue; + } + + //check inside + Vector2 tg = r.orthogonal(); + float s = tg.dot(center) - tg.dot(a); + if (s < 0.0f) { + side_plus++; + } else { + side_minus++; + } + + //check ray box + r /= l; + Vector2 ir(1.0f / r.x, 1.0f / r.y); + + // lb is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner + // r.org is origin of ray + Vector2 t13 = (position - a) * ir; + Vector2 t24 = (end - a) * ir; + + float tmin = MAX(MIN(t13.x, t24.x), MIN(t13.y, t24.y)); + float tmax = MIN(MAX(t13.x, t24.x), MAX(t13.y, t24.y)); + + // if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us + if (tmax < 0 || tmin > tmax || tmin >= l) { + continue; + } + + return true; + } + + if (side_plus * side_minus == 0) { + return true; //all inside + } else { + return false; + } + } + + _FORCE_INLINE_ void set_end(const Vector2 &p_end) { + size = p_end - position; + } + + _FORCE_INLINE_ Vector2 get_end() const { + return position + size; + } + + operator String() const; + + Rect2() {} + Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : + position(Point2(p_x, p_y)), + size(Size2(p_width, p_height)) { + } + Rect2(const Point2 &p_pos, const Size2 &p_size) : + position(p_pos), + size(p_size) { + } +}; + +#line 0 + +#line 1 "sfw/core/rect2i.h" + +/*************************************************************************/ +/* rect2i.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Rect2i { + Point2i position; + Size2i size; + + const Point2i &get_position() const { return position; } + void set_position(const Point2i &p_position) { position = p_position; } + const Size2i &get_size() const { return size; } + void set_size(const Size2i &p_size) { size = p_size; } + + int get_area() const { return size.width * size.height; } + + _FORCE_INLINE_ Vector2i get_center() const { return position + (size / 2); } + + inline bool intersects(const Rect2i &p_rect) const { + if (position.x > (p_rect.position.x + p_rect.size.width)) { + return false; + } + if ((position.x + size.width) < p_rect.position.x) { + return false; + } + if (position.y > (p_rect.position.y + p_rect.size.height)) { + return false; + } + if ((position.y + size.height) < p_rect.position.y) { + return false; + } + + return true; + } + + inline bool encloses(const Rect2i &p_rect) const { + return (p_rect.position.x >= position.x) && (p_rect.position.y >= position.y) && + ((p_rect.position.x + p_rect.size.x) < (position.x + size.x)) && + ((p_rect.position.y + p_rect.size.y) < (position.y + size.y)); + } + + _FORCE_INLINE_ bool has_no_area() const { + return (size.x <= 0 || size.y <= 0); + } + + inline Rect2i clip(const Rect2i &p_rect) const { /// return a clipped rect + + Rect2i new_rect = p_rect; + + if (!intersects(new_rect)) { + return Rect2i(); + } + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2 p_rect_end = p_rect.position + p_rect.size; + Point2 end = position + size; + + new_rect.size.x = (int)(MIN(p_rect_end.x, end.x) - new_rect.position.x); + new_rect.size.y = (int)(MIN(p_rect_end.y, end.y) - new_rect.position.y); + + return new_rect; + } + + // Returns the instersection between two Rect2is or an empty Rect2i if there is no intersection + inline Rect2i intersection(const Rect2i &p_rect) const { + Rect2i new_rect = p_rect; + + if (!intersects(new_rect)) { + return Rect2i(); + } + + new_rect.position.x = MAX(p_rect.position.x, position.x); + new_rect.position.y = MAX(p_rect.position.y, position.y); + + Point2i p_rect_end = p_rect.position + p_rect.size; + Point2i end = position + size; + + new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; + new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + + return new_rect; + } + + inline Rect2i merge(const Rect2i &p_rect) const { ///< return a merged rect + + Rect2i new_rect; + + new_rect.position.x = MIN(p_rect.position.x, position.x); + new_rect.position.y = MIN(p_rect.position.y, position.y); + + new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); + new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); + + new_rect.size = new_rect.size - new_rect.position; //make relative again + + return new_rect; + } + + bool has_point(const Point2i &p_point) const { + if (p_point.x < position.x) { + return false; + } + if (p_point.y < position.y) { + return false; + } + + if (p_point.x >= (position.x + size.x)) { + return false; + } + if (p_point.y >= (position.y + size.y)) { + return false; + } + + return true; + } + + bool operator==(const Rect2i &p_rect) const { return position == p_rect.position && size == p_rect.size; } + bool operator!=(const Rect2i &p_rect) const { return position != p_rect.position || size != p_rect.size; } + + Rect2i grow(int p_by) const { + Rect2i g = *this; + g.position.x -= p_by; + g.position.y -= p_by; + g.size.width += p_by * 2; + g.size.height += p_by * 2; + return g; + } + + void grow_by(int p_by) { + position.x -= p_by; + position.y -= p_by; + size.width += p_by * 2; + size.height += p_by * 2; + } + + inline Rect2i grow_margin(Margin p_margin, int p_amount) const { + Rect2i g = *this; + g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0, + (MARGIN_TOP == p_margin) ? p_amount : 0, + (MARGIN_RIGHT == p_margin) ? p_amount : 0, + (MARGIN_BOTTOM == p_margin) ? p_amount : 0); + return g; + } + + inline Rect2i grow_side(Side p_side, int p_amount) const { + Rect2i g = *this; + g = g.grow_individual((SIDE_LEFT == p_side) ? p_amount : 0, + (SIDE_TOP == p_side) ? p_amount : 0, + (SIDE_RIGHT == p_side) ? p_amount : 0, + (SIDE_BOTTOM == p_side) ? p_amount : 0); + return g; + } + + inline Rect2i grow_individual(int p_left, int p_top, int p_right, int p_bottom) const { + Rect2i g = *this; + g.position.x -= p_left; + g.position.y -= p_top; + g.size.width += p_left + p_right; + g.size.height += p_top + p_bottom; + + return g; + } + + _FORCE_INLINE_ Rect2i expand(const Vector2i &p_vector) const { + Rect2i r = *this; + r.expand_to(p_vector); + return r; + } + + inline void expand_to(const Point2i &p_vector) { + Point2i begin = position; + Point2i end = position + size; + + if (p_vector.x < begin.x) { + begin.x = p_vector.x; + } + if (p_vector.y < begin.y) { + begin.y = p_vector.y; + } + + if (p_vector.x > end.x) { + end.x = p_vector.x; + } + if (p_vector.y > end.y) { + end.y = p_vector.y; + } + + position = begin; + size = end - begin; + } + + _FORCE_INLINE_ Rect2i abs() const { + return Rect2i(Point2i(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); + } + + _FORCE_INLINE_ void set_end(const Vector2i &p_end) { + size = p_end - position; + } + + _FORCE_INLINE_ Vector2i get_end() const { + return position + size; + } + + Rect2 to_rect2() const { return Rect2(position, size); } + + operator String() const; + operator Rect2() const { return Rect2(position, size); } + + Rect2i(const Rect2 &p_r2) : + position(p_r2.position), + size(p_r2.size) { + } + Rect2i() {} + Rect2i(int p_x, int p_y, int p_width, int p_height) : + position(Point2(p_x, p_y)), + size(Size2(p_width, p_height)) { + } + Rect2i(const Point2 &p_pos, const Size2 &p_size) : + position(p_pos), + size(p_size) { + } +}; + +#line 0 + +#line 1 "sfw/core/vector3.h" + +/*************************************************************************/ +/* vector3.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct Basis; + +struct _NO_DISCARD_CLASS_ Vector3 { + static const int AXIS_COUNT = 3; + + enum Axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + }; + + union { + struct { + real_t x; + real_t y; + real_t z; + }; + + real_t coord[3]; + }; + + _FORCE_INLINE_ const real_t &operator[](int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 3); + return coord[p_axis]; + } + + _FORCE_INLINE_ real_t &operator[](int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 3); + return coord[p_axis]; + } + + void set_axis(int p_axis, real_t p_value); + real_t get_axis(int p_axis) const; + + _FORCE_INLINE_ void set_all(real_t p_value) { + x = y = z = p_value; + } + + _FORCE_INLINE_ int min_axis() const { + return x < y ? (x < z ? 0 : 2) : (y < z ? 1 : 2); + } + + _FORCE_INLINE_ int max_axis() const { + return x < y ? (y < z ? 2 : 1) : (x < z ? 2 : 0); + } + + _FORCE_INLINE_ real_t length() const; + _FORCE_INLINE_ real_t length_squared() const; + + _FORCE_INLINE_ void normalize(); + _FORCE_INLINE_ Vector3 normalized() const; + _FORCE_INLINE_ bool is_normalized() const; + _FORCE_INLINE_ Vector3 inverse() const; + Vector3 limit_length(const real_t p_len = 1.0) const; + + _FORCE_INLINE_ void zero(); + + void snap(const Vector3 &p_val); + Vector3 snapped(const Vector3 &p_val) const; + + void rotate(const Vector3 &p_axis, real_t p_phi); + Vector3 rotated(const Vector3 &p_axis, real_t p_phi) const; + + /* Static Methods between 2 vector3s */ + + _FORCE_INLINE_ Vector3 linear_interpolate(const Vector3 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, real_t p_weight) const; + _FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, real_t p_weight) const; + _FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const; + + Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const; + + _FORCE_INLINE_ Vector3 cross(const Vector3 &p_b) const; + _FORCE_INLINE_ real_t dot(const Vector3 &p_b) const; + Basis outer(const Vector3 &p_b) const; + Basis to_diagonal_matrix() const; + + _FORCE_INLINE_ Vector3 abs() const; + _FORCE_INLINE_ Vector3 floor() const; + _FORCE_INLINE_ Vector3 sign() const; + _FORCE_INLINE_ Vector3 ceil() const; + _FORCE_INLINE_ Vector3 round() const; + Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const; + + _FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const; + _FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const; + + _FORCE_INLINE_ Vector3 posmod(const real_t p_mod) const; + _FORCE_INLINE_ Vector3 posmodv(const Vector3 &p_modv) const; + _FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const; + + _FORCE_INLINE_ real_t angle_to(const Vector3 &p_to) const; + _FORCE_INLINE_ real_t signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const; + _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_to) const; + + _FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const; + _FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const; + _FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const; + + bool is_equal_approx(const Vector3 &p_v) const; + inline bool is_equal_approx(const Vector3 &p_v, real_t p_tolerance) const; + inline bool is_equal_approxt(const Vector3 &p_v, real_t p_tolerance) const; + + /* Operators */ + + _FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v); + _FORCE_INLINE_ Vector3 operator+(const Vector3 &p_v) const; + _FORCE_INLINE_ Vector3 &operator-=(const Vector3 &p_v); + _FORCE_INLINE_ Vector3 operator-(const Vector3 &p_v) const; + _FORCE_INLINE_ Vector3 &operator*=(const Vector3 &p_v); + _FORCE_INLINE_ Vector3 operator*(const Vector3 &p_v) const; + _FORCE_INLINE_ Vector3 &operator/=(const Vector3 &p_v); + _FORCE_INLINE_ Vector3 operator/(const Vector3 &p_v) const; + + _FORCE_INLINE_ Vector3 &operator*=(real_t p_scalar); + _FORCE_INLINE_ Vector3 operator*(real_t p_scalar) const; + _FORCE_INLINE_ Vector3 &operator/=(real_t p_scalar); + _FORCE_INLINE_ Vector3 operator/(real_t p_scalar) const; + + _FORCE_INLINE_ Vector3 operator-() const; + + _FORCE_INLINE_ bool operator==(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator!=(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator<(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator<=(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator>(const Vector3 &p_v) const; + _FORCE_INLINE_ bool operator>=(const Vector3 &p_v) const; + + operator String() const; + + _FORCE_INLINE_ Vector3(real_t p_x, real_t p_y, real_t p_z) { + x = p_x; + y = p_y; + z = p_z; + } + _FORCE_INLINE_ Vector3() { x = y = z = 0; } +}; + +Vector3 Vector3::cross(const Vector3 &p_b) const { + Vector3 ret( + (y * p_b.z) - (z * p_b.y), + (z * p_b.x) - (x * p_b.z), + (x * p_b.y) - (y * p_b.x)); + + return ret; +} + +real_t Vector3::dot(const Vector3 &p_b) const { + return x * p_b.x + y * p_b.y + z * p_b.z; +} + +Vector3 Vector3::abs() const { + return Vector3(Math::abs(x), Math::abs(y), Math::abs(z)); +} + +Vector3 Vector3::sign() const { + return Vector3(SGN(x), SGN(y), SGN(z)); +} + +Vector3 Vector3::floor() const { + return Vector3(Math::floor(x), Math::floor(y), Math::floor(z)); +} + +Vector3 Vector3::ceil() const { + return Vector3(Math::ceil(x), Math::ceil(y), Math::ceil(z)); +} + +Vector3 Vector3::round() const { + return Vector3(Math::round(x), Math::round(y), Math::round(z)); +} + +Vector3 Vector3::linear_interpolate(const Vector3 &p_to, real_t p_weight) const { + return Vector3( + x + (p_weight * (p_to.x - x)), + y + (p_weight * (p_to.y - y)), + z + (p_weight * (p_to.z - z))); +} + +Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const { + // This method seems more complicated than it really is, since we write out + // the internals of some methods for efficiency (mainly, checking length). + real_t start_length_sq = length_squared(); + real_t end_length_sq = p_to.length_squared(); + if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) { + // Zero length vectors have no angle, so the best we can do is either lerp or throw an error. + return linear_interpolate(p_to, p_weight); + } + Vector3 axis = cross(p_to); + real_t axis_length_sq = axis.length_squared(); + if (unlikely(axis_length_sq == 0.0f)) { + // Colinear vectors have no rotation axis or angle between them, so the best we can do is lerp. + return linear_interpolate(p_to, p_weight); + } + axis /= Math::sqrt(axis_length_sq); + real_t start_length = Math::sqrt(start_length_sq); + real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight); + real_t angle = angle_to(p_to); + return rotated(axis, angle * p_weight) * (result_length / start_length); +} + +Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const { + Vector3 res = *this; + res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight); + res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight); + res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight); + return res; +} + +Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const { + Vector3 res = *this; + + /* Formula from Wikipedia article on Bezier curves. */ + real_t omt = (1.0 - p_t); + real_t omt2 = omt * omt; + real_t omt3 = omt2 * omt; + real_t t2 = p_t * p_t; + real_t t3 = t2 * p_t; + + return res * omt3 + p_control_1 * omt2 * p_t * 3.0 + p_control_2 * omt * t2 * 3.0 + p_end * t3; +} + +real_t Vector3::distance_to(const Vector3 &p_to) const { + return (p_to - *this).length(); +} + +real_t Vector3::distance_squared_to(const Vector3 &p_to) const { + return (p_to - *this).length_squared(); +} + +Vector3 Vector3::posmod(const real_t p_mod) const { + return Vector3(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod)); +} + +Vector3 Vector3::posmodv(const Vector3 &p_modv) const { + return Vector3(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z)); +} + +Vector3 Vector3::project(const Vector3 &p_to) const { + return p_to * (dot(p_to) / p_to.length_squared()); +} + +real_t Vector3::angle_to(const Vector3 &p_to) const { + return Math::atan2(cross(p_to).length(), dot(p_to)); +} + +real_t Vector3::signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const { + Vector3 cross_to = cross(p_to); + real_t unsigned_angle = Math::atan2(cross_to.length(), dot(p_to)); + real_t sign = cross_to.dot(p_axis); + return (sign < 0) ? -unsigned_angle : unsigned_angle; +} + +Vector3 Vector3::direction_to(const Vector3 &p_to) const { + Vector3 ret(p_to.x - x, p_to.y - y, p_to.z - z); + ret.normalize(); + return ret; +} + +/* Operators */ + +Vector3 &Vector3::operator+=(const Vector3 &p_v) { + x += p_v.x; + y += p_v.y; + z += p_v.z; + return *this; +} + +Vector3 Vector3::operator+(const Vector3 &p_v) const { + return Vector3(x + p_v.x, y + p_v.y, z + p_v.z); +} + +Vector3 &Vector3::operator-=(const Vector3 &p_v) { + x -= p_v.x; + y -= p_v.y; + z -= p_v.z; + return *this; +} +Vector3 Vector3::operator-(const Vector3 &p_v) const { + return Vector3(x - p_v.x, y - p_v.y, z - p_v.z); +} + +Vector3 &Vector3::operator*=(const Vector3 &p_v) { + x *= p_v.x; + y *= p_v.y; + z *= p_v.z; + return *this; +} +Vector3 Vector3::operator*(const Vector3 &p_v) const { + return Vector3(x * p_v.x, y * p_v.y, z * p_v.z); +} + +Vector3 &Vector3::operator/=(const Vector3 &p_v) { + x /= p_v.x; + y /= p_v.y; + z /= p_v.z; + return *this; +} + +Vector3 Vector3::operator/(const Vector3 &p_v) const { + return Vector3(x / p_v.x, y / p_v.y, z / p_v.z); +} + +Vector3 &Vector3::operator*=(real_t p_scalar) { + x *= p_scalar; + y *= p_scalar; + z *= p_scalar; + return *this; +} + +_FORCE_INLINE_ Vector3 operator*(real_t p_scalar, const Vector3 &p_vec) { + return p_vec * p_scalar; +} + +Vector3 Vector3::operator*(real_t p_scalar) const { + return Vector3(x * p_scalar, y * p_scalar, z * p_scalar); +} + +Vector3 &Vector3::operator/=(real_t p_scalar) { + x /= p_scalar; + y /= p_scalar; + z /= p_scalar; + return *this; +} + +Vector3 Vector3::operator/(real_t p_scalar) const { + return Vector3(x / p_scalar, y / p_scalar, z / p_scalar); +} + +Vector3 Vector3::operator-() const { + return Vector3(-x, -y, -z); +} + +bool Vector3::operator==(const Vector3 &p_v) const { + return x == p_v.x && y == p_v.y && z == p_v.z; +} + +bool Vector3::operator!=(const Vector3 &p_v) const { + return x != p_v.x || y != p_v.y || z != p_v.z; +} + +bool Vector3::operator<(const Vector3 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z < p_v.z; + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector3::operator>(const Vector3 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z > p_v.z; + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +bool Vector3::operator<=(const Vector3 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z <= p_v.z; + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector3::operator>=(const Vector3 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z >= p_v.z; + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +_FORCE_INLINE_ Vector3 vec3_cross(const Vector3 &p_a, const Vector3 &p_b) { + return p_a.cross(p_b); +} + +_FORCE_INLINE_ real_t vec3_dot(const Vector3 &p_a, const Vector3 &p_b) { + return p_a.dot(p_b); +} + +real_t Vector3::length() const { + real_t x2 = x * x; + real_t y2 = y * y; + real_t z2 = z * z; + + return Math::sqrt(x2 + y2 + z2); +} + +real_t Vector3::length_squared() const { + real_t x2 = x * x; + real_t y2 = y * y; + real_t z2 = z * z; + + return x2 + y2 + z2; +} + +void Vector3::normalize() { + real_t lengthsq = length_squared(); + if (lengthsq == 0) { + x = y = z = 0; + } else { + real_t length = Math::sqrt(lengthsq); + x /= length; + y /= length; + z /= length; + } +} + +Vector3 Vector3::normalized() const { + Vector3 v = *this; + v.normalize(); + return v; +} + +bool Vector3::is_normalized() const { + // use length_squared() instead of length() to avoid sqrt(), makes it more stringent. + return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); +} + +Vector3 Vector3::inverse() const { + return Vector3(1 / x, 1 / y, 1 / z); +} + +void Vector3::zero() { + x = y = z = 0; +} + +// slide returns the component of the vector along the given plane, specified by its normal vector. +Vector3 Vector3::slide(const Vector3 &p_normal) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 must be normalized."); +#endif + return *this - p_normal * this->dot(p_normal); +} + +Vector3 Vector3::bounce(const Vector3 &p_normal) const { + return -reflect(p_normal); +} + +Vector3 Vector3::reflect(const Vector3 &p_normal) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!p_normal.is_normalized(), Vector3(), "The normal Vector3 must be normalized."); +#endif + return 2 * p_normal * this->dot(p_normal) - *this; +} + +bool Vector3::is_equal_approx(const Vector3 &p_v, real_t p_tolerance) const { + return Math::is_equal_approx(x, p_v.x, p_tolerance) && Math::is_equal_approx(y, p_v.y, p_tolerance) && Math::is_equal_approx(z, p_v.z, p_tolerance); +} + +bool Vector3::is_equal_approxt(const Vector3 &p_v, real_t p_tolerance) const { + return Math::is_equal_approx(x, p_v.x, p_tolerance) && Math::is_equal_approx(y, p_v.y, p_tolerance) && Math::is_equal_approx(z, p_v.z, p_tolerance); +} + +#line 0 + +#line 1 "sfw/core/vector3i.h" + +/*************************************************************************/ +/* vector3i.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +class String; +struct Vector3; + +struct _NO_DISCARD_CLASS_ Vector3i { + enum Axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + }; + + union { + struct { + int32_t x; + int32_t y; + int32_t z; + }; + + int32_t coord[3]; + }; + + _FORCE_INLINE_ const int32_t &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 3); + return coord[p_axis]; + } + + _FORCE_INLINE_ int32_t &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 3); + return coord[p_axis]; + } + + void set_axis(const int p_axis, const int32_t p_value); + int32_t get_axis(const int p_axis) const; + + _FORCE_INLINE_ void set_all(int32_t p_value) { + x = y = z = p_value; + } + + Vector3i::Axis min_axis() const; + Vector3i::Axis max_axis() const; + + _FORCE_INLINE_ int64_t length_squared() const; + _FORCE_INLINE_ double length() const; + + _FORCE_INLINE_ void zero(); + + _FORCE_INLINE_ Vector3i abs() const; + _FORCE_INLINE_ Vector3i sign() const; + Vector3i clamp(const Vector3i &p_min, const Vector3i &p_max) const; + + _FORCE_INLINE_ Vector3i linear_interpolate(const Vector3i &p_to, real_t p_weight) const; + + /* Operators */ + + _FORCE_INLINE_ Vector3i &operator+=(const Vector3i &p_v); + _FORCE_INLINE_ Vector3i operator+(const Vector3i &p_v) const; + _FORCE_INLINE_ Vector3i &operator-=(const Vector3i &p_v); + _FORCE_INLINE_ Vector3i operator-(const Vector3i &p_v) const; + _FORCE_INLINE_ Vector3i &operator*=(const Vector3i &p_v); + _FORCE_INLINE_ Vector3i operator*(const Vector3i &p_v) const; + _FORCE_INLINE_ Vector3i &operator/=(const Vector3i &p_v); + _FORCE_INLINE_ Vector3i operator/(const Vector3i &p_v) const; + _FORCE_INLINE_ Vector3i &operator%=(const Vector3i &p_v); + _FORCE_INLINE_ Vector3i operator%(const Vector3i &p_v) const; + + _FORCE_INLINE_ Vector3i &operator*=(const int32_t p_scalar); + _FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector3i &operator/=(const int32_t p_scalar); + _FORCE_INLINE_ Vector3i operator/(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector3i &operator%=(const int32_t p_scalar); + _FORCE_INLINE_ Vector3i operator%(const int32_t p_scalar) const; + + _FORCE_INLINE_ Vector3i operator-() const; + + _FORCE_INLINE_ bool operator==(const Vector3i &p_v) const; + _FORCE_INLINE_ bool operator!=(const Vector3i &p_v) const; + _FORCE_INLINE_ bool operator<(const Vector3i &p_v) const; + _FORCE_INLINE_ bool operator<=(const Vector3i &p_v) const; + _FORCE_INLINE_ bool operator>(const Vector3i &p_v) const; + _FORCE_INLINE_ bool operator>=(const Vector3i &p_v) const; + + Vector3 to_vector3() const; + + operator String() const; + operator Vector3() const; + + _FORCE_INLINE_ Vector3i() { + x = 0; + y = 0; + z = 0; + } + _FORCE_INLINE_ Vector3i(const int32_t p_x, const int32_t p_y, const int32_t p_z) { + x = p_x; + y = p_y; + z = p_z; + } +}; + +int64_t Vector3i::length_squared() const { + return x * (int64_t)x + y * (int64_t)y + z * (int64_t)z; +} + +double Vector3i::length() const { + return Math::sqrt((double)length_squared()); +} + +Vector3i Vector3i::abs() const { + return Vector3i(ABS(x), ABS(y), ABS(z)); +} + +Vector3i Vector3i::sign() const { + return Vector3i(SGN(x), SGN(y), SGN(z)); +} + +Vector3i Vector3i::linear_interpolate(const Vector3i &p_to, real_t p_weight) const { + return Vector3i( + x + (p_weight * (p_to.x - x)), + y + (p_weight * (p_to.y - y)), + z + (p_weight * (p_to.z - z))); +} + +/* Operators */ + +Vector3i &Vector3i::operator+=(const Vector3i &p_v) { + x += p_v.x; + y += p_v.y; + z += p_v.z; + return *this; +} + +Vector3i Vector3i::operator+(const Vector3i &p_v) const { + return Vector3i(x + p_v.x, y + p_v.y, z + p_v.z); +} + +Vector3i &Vector3i::operator-=(const Vector3i &p_v) { + x -= p_v.x; + y -= p_v.y; + z -= p_v.z; + return *this; +} + +Vector3i Vector3i::operator-(const Vector3i &p_v) const { + return Vector3i(x - p_v.x, y - p_v.y, z - p_v.z); +} + +Vector3i &Vector3i::operator*=(const Vector3i &p_v) { + x *= p_v.x; + y *= p_v.y; + z *= p_v.z; + return *this; +} + +Vector3i Vector3i::operator*(const Vector3i &p_v) const { + return Vector3i(x * p_v.x, y * p_v.y, z * p_v.z); +} + +Vector3i &Vector3i::operator/=(const Vector3i &p_v) { + x /= p_v.x; + y /= p_v.y; + z /= p_v.z; + return *this; +} + +Vector3i Vector3i::operator/(const Vector3i &p_v) const { + return Vector3i(x / p_v.x, y / p_v.y, z / p_v.z); +} + +Vector3i &Vector3i::operator%=(const Vector3i &p_v) { + x %= p_v.x; + y %= p_v.y; + z %= p_v.z; + return *this; +} + +Vector3i Vector3i::operator%(const Vector3i &p_v) const { + return Vector3i(x % p_v.x, y % p_v.y, z % p_v.z); +} + +Vector3i &Vector3i::operator*=(const int32_t p_scalar) { + x *= p_scalar; + y *= p_scalar; + z *= p_scalar; + return *this; +} + +Vector3i Vector3i::operator*(const int32_t p_scalar) const { + return Vector3i(x * p_scalar, y * p_scalar, z * p_scalar); +} + +// Multiplication operators required to workaround issues with LLVM using implicit conversion. + +_FORCE_INLINE_ Vector3i operator*(const int32_t p_scalar, const Vector3i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector3i operator*(const int64_t p_scalar, const Vector3i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector3i operator*(const float p_scalar, const Vector3i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector3i operator*(const double p_scalar, const Vector3i &p_vector) { + return p_vector * p_scalar; +} + +Vector3i &Vector3i::operator/=(const int32_t p_scalar) { + x /= p_scalar; + y /= p_scalar; + z /= p_scalar; + return *this; +} + +Vector3i Vector3i::operator/(const int32_t p_scalar) const { + return Vector3i(x / p_scalar, y / p_scalar, z / p_scalar); +} + +Vector3i &Vector3i::operator%=(const int32_t p_scalar) { + x %= p_scalar; + y %= p_scalar; + z %= p_scalar; + return *this; +} + +Vector3i Vector3i::operator%(const int32_t p_scalar) const { + return Vector3i(x % p_scalar, y % p_scalar, z % p_scalar); +} + +Vector3i Vector3i::operator-() const { + return Vector3i(-x, -y, -z); +} + +bool Vector3i::operator==(const Vector3i &p_v) const { + return (x == p_v.x && y == p_v.y && z == p_v.z); +} + +bool Vector3i::operator!=(const Vector3i &p_v) const { + return (x != p_v.x || y != p_v.y || z != p_v.z); +} + +bool Vector3i::operator<(const Vector3i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z < p_v.z; + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector3i::operator>(const Vector3i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z > p_v.z; + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +bool Vector3i::operator<=(const Vector3i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z <= p_v.z; + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector3i::operator>=(const Vector3i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + return z >= p_v.z; + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +void Vector3i::zero() { + x = y = z = 0; +} + +typedef Vector3i Size3i; +typedef Vector3i Point3i; + +#line 0 + +#line 1 "sfw/core/vector4.h" + +/*************************************************************************/ +/* vector4.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Vector4 { + enum Axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + AXIS_W, + }; + + union { + struct { + real_t x; + real_t y; + real_t z; + real_t w; + }; + real_t components[4]; + }; + + _FORCE_INLINE_ real_t &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 4); + return components[p_axis]; + } + _FORCE_INLINE_ const real_t &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 4); + return components[p_axis]; + } + + _FORCE_INLINE_ void set_all(const real_t p_value); + + void set_axis(const int p_axis, const real_t p_value); + real_t get_axis(const int p_axis) const; + + Vector4::Axis min_axis() const; + Vector4::Axis max_axis() const; + + _FORCE_INLINE_ real_t length_squared() const; + bool is_equal_approx(const Vector4 &p_vec4) const; + real_t length() const; + void normalize(); + Vector4 normalized() const; + bool is_normalized() const; + Vector4 limit_length(const real_t p_len = 1.0) const; + + _FORCE_INLINE_ void zero(); + + real_t distance_to(const Vector4 &p_to) const; + real_t distance_squared_to(const Vector4 &p_to) const; + Vector4 direction_to(const Vector4 &p_to) const; + + Vector4 abs() const; + Vector4 sign() const; + Vector4 floor() const; + Vector4 ceil() const; + Vector4 round() const; + + Vector4 linear_interpolate(const Vector4 &p_to, const real_t p_weight) const; + Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const; + + Vector4 posmod(const real_t p_mod) const; + Vector4 posmodv(const Vector4 &p_modv) const; + void snap(const Vector4 &p_step); + Vector4 snapped(const Vector4 &p_step) const; + Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const; + + Vector4 inverse() const; + _FORCE_INLINE_ real_t dot(const Vector4 &p_vec4) const; + + _FORCE_INLINE_ void operator+=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator-=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator*=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator/=(const Vector4 &p_vec4); + _FORCE_INLINE_ void operator*=(const real_t &s); + _FORCE_INLINE_ void operator/=(const real_t &s); + _FORCE_INLINE_ Vector4 operator+(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator-(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator*(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator/(const Vector4 &p_vec4) const; + _FORCE_INLINE_ Vector4 operator-() const; + _FORCE_INLINE_ Vector4 operator*(const real_t &s) const; + _FORCE_INLINE_ Vector4 operator/(const real_t &s) const; + + _FORCE_INLINE_ bool operator==(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator!=(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator>(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator<(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator>=(const Vector4 &p_vec4) const; + _FORCE_INLINE_ bool operator<=(const Vector4 &p_vec4) const; + + operator String() const; + + _FORCE_INLINE_ Vector4() { + x = 0; + y = 0; + z = 0; + w = 0; + } + + _FORCE_INLINE_ Vector4(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), + y(p_y), + z(p_z), + w(p_w) { + } + + Vector4(const Vector4 &p_vec4) : + x(p_vec4.x), + y(p_vec4.y), + z(p_vec4.z), + w(p_vec4.w) { + } + + void operator=(const Vector4 &p_vec4) { + x = p_vec4.x; + y = p_vec4.y; + z = p_vec4.z; + w = p_vec4.w; + } +}; + +void Vector4::set_all(const real_t p_value) { + x = y = z = p_value; +} + +real_t Vector4::dot(const Vector4 &p_vec4) const { + return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w; +} + +real_t Vector4::length_squared() const { + return dot(*this); +} + +void Vector4::zero() { + x = y = z = 0; +} + +void Vector4::operator+=(const Vector4 &p_vec4) { + x += p_vec4.x; + y += p_vec4.y; + z += p_vec4.z; + w += p_vec4.w; +} + +void Vector4::operator-=(const Vector4 &p_vec4) { + x -= p_vec4.x; + y -= p_vec4.y; + z -= p_vec4.z; + w -= p_vec4.w; +} + +void Vector4::operator*=(const Vector4 &p_vec4) { + x *= p_vec4.x; + y *= p_vec4.y; + z *= p_vec4.z; + w *= p_vec4.w; +} + +void Vector4::operator/=(const Vector4 &p_vec4) { + x /= p_vec4.x; + y /= p_vec4.y; + z /= p_vec4.z; + w /= p_vec4.w; +} +void Vector4::operator*=(const real_t &s) { + x *= s; + y *= s; + z *= s; + w *= s; +} + +void Vector4::operator/=(const real_t &s) { + *this *= 1.0f / s; +} + +Vector4 Vector4::operator+(const Vector4 &p_vec4) const { + return Vector4(x + p_vec4.x, y + p_vec4.y, z + p_vec4.z, w + p_vec4.w); +} + +Vector4 Vector4::operator-(const Vector4 &p_vec4) const { + return Vector4(x - p_vec4.x, y - p_vec4.y, z - p_vec4.z, w - p_vec4.w); +} + +Vector4 Vector4::operator*(const Vector4 &p_vec4) const { + return Vector4(x * p_vec4.x, y * p_vec4.y, z * p_vec4.z, w * p_vec4.w); +} + +Vector4 Vector4::operator/(const Vector4 &p_vec4) const { + return Vector4(x / p_vec4.x, y / p_vec4.y, z / p_vec4.z, w / p_vec4.w); +} + +Vector4 Vector4::operator-() const { + return Vector4(-x, -y, -z, -w); +} + +Vector4 Vector4::operator*(const real_t &s) const { + return Vector4(x * s, y * s, z * s, w * s); +} + +Vector4 Vector4::operator/(const real_t &s) const { + return *this * (1.0f / s); +} + +bool Vector4::operator==(const Vector4 &p_vec4) const { + return x == p_vec4.x && y == p_vec4.y && z == p_vec4.z && w == p_vec4.w; +} + +bool Vector4::operator!=(const Vector4 &p_vec4) const { + return x != p_vec4.x || y != p_vec4.y || z != p_vec4.z || w != p_vec4.w; +} + +bool Vector4::operator<(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w < p_v.w; + } + return z < p_v.z; + } + return y < p_v.y; + } + return x < p_v.x; +} + +bool Vector4::operator>(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w > p_v.w; + } + return z > p_v.z; + } + return y > p_v.y; + } + return x > p_v.x; +} + +bool Vector4::operator<=(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w <= p_v.w; + } + return z < p_v.z; + } + return y < p_v.y; + } + return x < p_v.x; +} + +bool Vector4::operator>=(const Vector4 &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w >= p_v.w; + } + return z > p_v.z; + } + return y > p_v.y; + } + return x > p_v.x; +} + +_FORCE_INLINE_ Vector4 operator*(const float p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector4 operator*(const double p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector4 operator*(const int32_t p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +_FORCE_INLINE_ Vector4 operator*(const int64_t p_scalar, const Vector4 &p_vec) { + return p_vec * p_scalar; +} + +#line 0 + +#line 1 "sfw/core/vector4i.h" + +/*************************************************************************/ +/* vector4i.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +class String; +struct Vector4; + +struct _NO_DISCARD_CLASS_ Vector4i { + enum Axis { + AXIS_X, + AXIS_Y, + AXIS_Z, + AXIS_W, + }; + + union { + struct { + int32_t x; + int32_t y; + int32_t z; + int32_t w; + }; + + int32_t coord[4]; + }; + + _FORCE_INLINE_ const int32_t &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 4); + return coord[p_axis]; + } + + _FORCE_INLINE_ int32_t &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 4); + return coord[p_axis]; + } + + _FORCE_INLINE_ void set_all(const int32_t p_value); + + void set_axis(const int p_axis, const int32_t p_value); + int32_t get_axis(const int p_axis) const; + + Vector4i::Axis min_axis() const; + Vector4i::Axis max_axis() const; + + _FORCE_INLINE_ int64_t length_squared() const; + _FORCE_INLINE_ double length() const; + + _FORCE_INLINE_ void zero(); + + _FORCE_INLINE_ Vector4i abs() const; + _FORCE_INLINE_ Vector4i sign() const; + Vector4i clamp(const Vector4i &p_min, const Vector4i &p_max) const; + + Vector4i linear_interpolate(const Vector4i &p_to, const real_t p_weight) const; + + /* Operators */ + + _FORCE_INLINE_ Vector4i &operator+=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator+(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator-=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator-(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator*=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator*(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator/=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator/(const Vector4i &p_v) const; + _FORCE_INLINE_ Vector4i &operator%=(const Vector4i &p_v); + _FORCE_INLINE_ Vector4i operator%(const Vector4i &p_v) const; + + _FORCE_INLINE_ Vector4i &operator*=(const int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator/=(const int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator/(const int32_t p_scalar) const; + _FORCE_INLINE_ Vector4i &operator%=(const int32_t p_scalar); + _FORCE_INLINE_ Vector4i operator%(const int32_t p_scalar) const; + + _FORCE_INLINE_ Vector4i operator-() const; + + _FORCE_INLINE_ bool operator==(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator!=(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator<(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator<=(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator>(const Vector4i &p_v) const; + _FORCE_INLINE_ bool operator>=(const Vector4i &p_v) const; + + Vector4 to_vector4() const; + + operator String() const; + operator Vector4() const; + + _FORCE_INLINE_ Vector4i() { + x = 0; + y = 0; + z = 0; + w = 0; + } + + //Vector4i(const Vector4 &p_vec4); + + _FORCE_INLINE_ Vector4i(const int32_t p_x, const int32_t p_y, const int32_t p_z, const int32_t p_w) { + x = p_x; + y = p_y; + z = p_z; + w = p_w; + } +}; + +void Vector4i::set_all(const int32_t p_value) { + x = y = z = p_value; +} + +int64_t Vector4i::length_squared() const { + return x * (int64_t)x + y * (int64_t)y + z * (int64_t)z + w * (int64_t)w; +} + +double Vector4i::length() const { + return Math::sqrt((double)length_squared()); +} + +Vector4i Vector4i::abs() const { + return Vector4i(ABS(x), ABS(y), ABS(z), ABS(w)); +} + +Vector4i Vector4i::sign() const { + return Vector4i(SGN(x), SGN(y), SGN(z), SGN(w)); +} + +/* Operators */ + +Vector4i &Vector4i::operator+=(const Vector4i &p_v) { + x += p_v.x; + y += p_v.y; + z += p_v.z; + w += p_v.w; + return *this; +} + +Vector4i Vector4i::operator+(const Vector4i &p_v) const { + return Vector4i(x + p_v.x, y + p_v.y, z + p_v.z, w + p_v.w); +} + +Vector4i &Vector4i::operator-=(const Vector4i &p_v) { + x -= p_v.x; + y -= p_v.y; + z -= p_v.z; + w -= p_v.w; + return *this; +} + +Vector4i Vector4i::operator-(const Vector4i &p_v) const { + return Vector4i(x - p_v.x, y - p_v.y, z - p_v.z, w - p_v.w); +} + +Vector4i &Vector4i::operator*=(const Vector4i &p_v) { + x *= p_v.x; + y *= p_v.y; + z *= p_v.z; + w *= p_v.w; + return *this; +} + +Vector4i Vector4i::operator*(const Vector4i &p_v) const { + return Vector4i(x * p_v.x, y * p_v.y, z * p_v.z, w * p_v.w); +} + +Vector4i &Vector4i::operator/=(const Vector4i &p_v) { + x /= p_v.x; + y /= p_v.y; + z /= p_v.z; + w /= p_v.w; + return *this; +} + +Vector4i Vector4i::operator/(const Vector4i &p_v) const { + return Vector4i(x / p_v.x, y / p_v.y, z / p_v.z, w / p_v.w); +} + +Vector4i &Vector4i::operator%=(const Vector4i &p_v) { + x %= p_v.x; + y %= p_v.y; + z %= p_v.z; + w %= p_v.w; + return *this; +} + +Vector4i Vector4i::operator%(const Vector4i &p_v) const { + return Vector4i(x % p_v.x, y % p_v.y, z % p_v.z, w % p_v.w); +} + +Vector4i &Vector4i::operator*=(const int32_t p_scalar) { + x *= p_scalar; + y *= p_scalar; + z *= p_scalar; + w *= p_scalar; + return *this; +} + +Vector4i Vector4i::operator*(const int32_t p_scalar) const { + return Vector4i(x * p_scalar, y * p_scalar, z * p_scalar, w * p_scalar); +} + +// Multiplication operators required to workaround issues with LLVM using implicit conversion. + +_FORCE_INLINE_ Vector4i operator*(const int32_t p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector4i operator*(const int64_t p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector4i operator*(const float p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +_FORCE_INLINE_ Vector4i operator*(const double p_scalar, const Vector4i &p_vector) { + return p_vector * p_scalar; +} + +Vector4i &Vector4i::operator/=(const int32_t p_scalar) { + x /= p_scalar; + y /= p_scalar; + z /= p_scalar; + w /= p_scalar; + return *this; +} + +Vector4i Vector4i::operator/(const int32_t p_scalar) const { + return Vector4i(x / p_scalar, y / p_scalar, z / p_scalar, w / p_scalar); +} + +Vector4i &Vector4i::operator%=(const int32_t p_scalar) { + x %= p_scalar; + y %= p_scalar; + z %= p_scalar; + w %= p_scalar; + return *this; +} + +Vector4i Vector4i::operator%(const int32_t p_scalar) const { + return Vector4i(x % p_scalar, y % p_scalar, z % p_scalar, w % p_scalar); +} + +Vector4i Vector4i::operator-() const { + return Vector4i(-x, -y, -z, -w); +} + +bool Vector4i::operator==(const Vector4i &p_v) const { + return (x == p_v.x && y == p_v.y && z == p_v.z && w == p_v.w); +} + +bool Vector4i::operator!=(const Vector4i &p_v) const { + return (x != p_v.x || y != p_v.y || z != p_v.z || w != p_v.w); +} + +bool Vector4i::operator<(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w < p_v.w; + } else { + return z < p_v.z; + } + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector4i::operator>(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w > p_v.w; + } else { + return z > p_v.z; + } + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +bool Vector4i::operator<=(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w <= p_v.w; + } else { + return z < p_v.z; + } + } else { + return y < p_v.y; + } + } else { + return x < p_v.x; + } +} + +bool Vector4i::operator>=(const Vector4i &p_v) const { + if (x == p_v.x) { + if (y == p_v.y) { + if (z == p_v.z) { + return w >= p_v.w; + } else { + return z > p_v.z; + } + } else { + return y > p_v.y; + } + } else { + return x > p_v.x; + } +} + +void Vector4i::zero() { + x = y = z = w = 0; +} + +typedef Vector4i Size4i; +typedef Vector4i Point4i; + +#line 0 + +#line 1 "sfw/core/plane.h" + +/*************************************************************************/ +/* plane.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Plane { + Vector3 normal; + real_t d; + + void set_normal(const Vector3 &p_normal); + _FORCE_INLINE_ Vector3 get_normal() const { return normal; }; ///Point is coplanar, CMP_EPSILON for precision + + void normalize(); + Plane normalized() const; + + /* Plane-Point operations */ + + _FORCE_INLINE_ Vector3 center() const { return normal * d; } + Vector3 get_any_point() const; + Vector3 get_any_perpendicular_normal() const; + + _FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane + _FORCE_INLINE_ real_t distance_to(const Vector3 &p_point) const; + _FORCE_INLINE_ bool has_point(const Vector3 &p_point, real_t _epsilon = CMP_EPSILON) const; + + /* intersections */ + + bool intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r_result = nullptr) const; + bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection) const; + bool intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 *p_intersection) const; + + _FORCE_INLINE_ Vector3 project(const Vector3 &p_point) const { + return p_point - normal * distance_to(p_point); + } + + /* misc */ + + Plane operator-() const { return Plane(-normal, -d); } + bool is_equal_approx(const Plane &p_plane) const; + bool is_equal_approx_any_side(const Plane &p_plane) const; + + _FORCE_INLINE_ bool operator==(const Plane &p_plane) const; + _FORCE_INLINE_ bool operator!=(const Plane &p_plane) const; + operator String() const; + + _FORCE_INLINE_ Plane() : + d(0) {} + _FORCE_INLINE_ Plane(real_t p_a, real_t p_b, real_t p_c, real_t p_d) : + normal(p_a, p_b, p_c), + d(p_d) {} + + _FORCE_INLINE_ Plane(const Vector3 &p_normal, real_t p_d); + _FORCE_INLINE_ Plane(const Vector3 &p_point, const Vector3 &p_normal); + _FORCE_INLINE_ Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir = CLOCKWISE); +}; + +bool Plane::is_point_over(const Vector3 &p_point) const { + return (normal.dot(p_point) > d); +} + +real_t Plane::distance_to(const Vector3 &p_point) const { + return (normal.dot(p_point) - d); +} + +bool Plane::has_point(const Vector3 &p_point, real_t _epsilon) const { + real_t dist = normal.dot(p_point) - d; + dist = ABS(dist); + return (dist <= _epsilon); +} + +Plane::Plane(const Vector3 &p_normal, real_t p_d) : + normal(p_normal), + d(p_d) { +} + +Plane::Plane(const Vector3 &p_point, const Vector3 &p_normal) : + normal(p_normal), + d(p_normal.dot(p_point)) { +} + +Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_point3, ClockDirection p_dir) { + if (p_dir == CLOCKWISE) { + normal = (p_point1 - p_point3).cross(p_point1 - p_point2); + } else { + normal = (p_point1 - p_point2).cross(p_point1 - p_point3); + } + + normal.normalize(); + d = normal.dot(p_point1); +} + +bool Plane::operator==(const Plane &p_plane) const { + return normal == p_plane.normal && d == p_plane.d; +} + +bool Plane::operator!=(const Plane &p_plane) const { + return normal != p_plane.normal || d != p_plane.d; +} + +#line 0 + +#line 1 "sfw/core/aabb.h" + +/*************************************************************************/ +/* aabb.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +/** + * AABB / AABB (Axis Aligned Bounding Box) + * This is implemented by a point (position) and the box size + */ + +struct _NO_DISCARD_CLASS_ AABB { + Vector3 position; + Vector3 size; + + real_t get_volume() const; /// get area + _FORCE_INLINE_ bool has_no_volume() const { + return (size.x <= 0 || size.y <= 0 || size.z <= 0); + } + + _FORCE_INLINE_ bool has_no_surface() const { + return (size.x <= 0 && size.y <= 0 && size.z <= 0); + } + + const Vector3 &get_position() const { return position; } + void set_position(const Vector3 &p_pos) { position = p_pos; } + const Vector3 &get_size() const { return size; } + void set_size(const Vector3 &p_size) { size = p_size; } + + bool operator==(const AABB &p_rval) const; + bool operator!=(const AABB &p_rval) const; + + bool is_equal_approx(const AABB &p_aabb) const; + _FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap + _FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap + _FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this + + AABB merge(const AABB &p_with) const; + void merge_with(const AABB &p_aabb); ///merge with another AABB + AABB intersection(const AABB &p_aabb) const; ///get box where two intersect, empty if no intersection occurs + bool intersects_segment(const Vector3 &p_from, const Vector3 &p_to, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const; + bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = nullptr, Vector3 *r_normal = nullptr) const; + _FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const; + + _FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const; + _FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const; + bool intersects_plane(const Plane &p_plane) const; + + _FORCE_INLINE_ bool has_point(const Vector3 &p_point) const; + _FORCE_INLINE_ Vector3 get_support(const Vector3 &p_normal) const; + + Vector3 get_longest_axis() const; + int get_longest_axis_index() const; + _FORCE_INLINE_ real_t get_longest_axis_size() const; + + Vector3 get_shortest_axis() const; + int get_shortest_axis_index() const; + _FORCE_INLINE_ real_t get_shortest_axis_size() const; + + AABB grow(real_t p_by) const; + _FORCE_INLINE_ void grow_by(real_t p_amount); + + void get_edge(int p_edge, Vector3 &r_from, Vector3 &r_to) const; + _FORCE_INLINE_ Vector3 get_endpoint(int p_point) const; + + AABB expand(const Vector3 &p_vector) const; + _FORCE_INLINE_ void project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const; + _FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */ + bool create_from_points(const Vector &p_points); + + _FORCE_INLINE_ AABB abs() const { + return AABB(Vector3(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0), position.z + MIN(size.z, 0)), size.abs()); + } + + //Variant intersects_segmentv(const Vector3 &p_from, const Vector3 &p_to) const; + //Variant intersects_rayv(const Vector3 &p_from, const Vector3 &p_dir) const; + + _FORCE_INLINE_ void quantize(real_t p_unit); + _FORCE_INLINE_ AABB quantized(real_t p_unit) const; + + _FORCE_INLINE_ void set_end(const Vector3 &p_end) { + size = p_end - position; + } + + _FORCE_INLINE_ Vector3 get_end() const { + return position + size; + } + + _FORCE_INLINE_ Vector3 get_center() const { + return position + (size * 0.5f); + } + + operator String() const; + + _FORCE_INLINE_ AABB() {} + inline AABB(const Vector3 &p_pos, const Vector3 &p_size) : + position(p_pos), + size(p_size) { + } +}; + +inline bool AABB::intersects(const AABB &p_aabb) const { + if (position.x >= (p_aabb.position.x + p_aabb.size.x)) { + return false; + } + if ((position.x + size.x) <= p_aabb.position.x) { + return false; + } + if (position.y >= (p_aabb.position.y + p_aabb.size.y)) { + return false; + } + if ((position.y + size.y) <= p_aabb.position.y) { + return false; + } + if (position.z >= (p_aabb.position.z + p_aabb.size.z)) { + return false; + } + if ((position.z + size.z) <= p_aabb.position.z) { + return false; + } + + return true; +} + +inline bool AABB::intersects_inclusive(const AABB &p_aabb) const { + if (position.x > (p_aabb.position.x + p_aabb.size.x)) { + return false; + } + if ((position.x + size.x) < p_aabb.position.x) { + return false; + } + if (position.y > (p_aabb.position.y + p_aabb.size.y)) { + return false; + } + if ((position.y + size.y) < p_aabb.position.y) { + return false; + } + if (position.z > (p_aabb.position.z + p_aabb.size.z)) { + return false; + } + if ((position.z + size.z) < p_aabb.position.z) { + return false; + } + + return true; +} + +inline bool AABB::encloses(const AABB &p_aabb) const { + Vector3 src_min = position; + Vector3 src_max = position + size; + Vector3 dst_min = p_aabb.position; + Vector3 dst_max = p_aabb.position + p_aabb.size; + + return ( + (src_min.x <= dst_min.x) && + (src_max.x > dst_max.x) && + (src_min.y <= dst_min.y) && + (src_max.y > dst_max.y) && + (src_min.z <= dst_min.z) && + (src_max.z > dst_max.z)); +} + +Vector3 AABB::get_support(const Vector3 &p_normal) const { + Vector3 half_extents = size * 0.5f; + Vector3 ofs = position + half_extents; + + return Vector3( + (p_normal.x > 0) ? -half_extents.x : half_extents.x, + (p_normal.y > 0) ? -half_extents.y : half_extents.y, + (p_normal.z > 0) ? -half_extents.z : half_extents.z) + + ofs; +} + +Vector3 AABB::get_endpoint(int p_point) const { + switch (p_point) { + case 0: + return Vector3(position.x, position.y, position.z); + case 1: + return Vector3(position.x, position.y, position.z + size.z); + case 2: + return Vector3(position.x, position.y + size.y, position.z); + case 3: + return Vector3(position.x, position.y + size.y, position.z + size.z); + case 4: + return Vector3(position.x + size.x, position.y, position.z); + case 5: + return Vector3(position.x + size.x, position.y, position.z + size.z); + case 6: + return Vector3(position.x + size.x, position.y + size.y, position.z); + case 7: + return Vector3(position.x + size.x, position.y + size.y, position.z + size.z); + }; + + ERR_FAIL_V(Vector3()); +} + +bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const { + Vector3 half_extents = size * 0.5f; + Vector3 ofs = position + half_extents; + + for (int i = 0; i < p_plane_count; i++) { + const Plane &p = p_planes[i]; + Vector3 point( + (p.normal.x > 0) ? -half_extents.x : half_extents.x, + (p.normal.y > 0) ? -half_extents.y : half_extents.y, + (p.normal.z > 0) ? -half_extents.z : half_extents.z); + point += ofs; + if (p.is_point_over(point)) { + return false; + } + } + + // Make sure all points in the shape aren't fully separated from the AABB on + // each axis. + int bad_point_counts_positive[3] = { 0 }; + int bad_point_counts_negative[3] = { 0 }; + + for (int k = 0; k < 3; k++) { + for (int i = 0; i < p_point_count; i++) { + if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) { + bad_point_counts_positive[k]++; + } + if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) { + bad_point_counts_negative[k]++; + } + } + + if (bad_point_counts_negative[k] == p_point_count) { + return false; + } + if (bad_point_counts_positive[k] == p_point_count) { + return false; + } + } + + return true; +} + +bool AABB::inside_convex_shape(const Plane *p_planes, int p_plane_count) const { + Vector3 half_extents = size * 0.5f; + Vector3 ofs = position + half_extents; + + for (int i = 0; i < p_plane_count; i++) { + const Plane &p = p_planes[i]; + Vector3 point( + (p.normal.x < 0) ? -half_extents.x : half_extents.x, + (p.normal.y < 0) ? -half_extents.y : half_extents.y, + (p.normal.z < 0) ? -half_extents.z : half_extents.z); + point += ofs; + if (p.is_point_over(point)) { + return false; + } + } + + return true; +} + +bool AABB::has_point(const Vector3 &p_point) const { + if (p_point.x < position.x) { + return false; + } + if (p_point.y < position.y) { + return false; + } + if (p_point.z < position.z) { + return false; + } + if (p_point.x > position.x + size.x) { + return false; + } + if (p_point.y > position.y + size.y) { + return false; + } + if (p_point.z > position.z + size.z) { + return false; + } + + return true; +} + +inline void AABB::expand_to(const Vector3 &p_vector) { + Vector3 begin = position; + Vector3 end = position + size; + + if (p_vector.x < begin.x) { + begin.x = p_vector.x; + } + if (p_vector.y < begin.y) { + begin.y = p_vector.y; + } + if (p_vector.z < begin.z) { + begin.z = p_vector.z; + } + + if (p_vector.x > end.x) { + end.x = p_vector.x; + } + if (p_vector.y > end.y) { + end.y = p_vector.y; + } + if (p_vector.z > end.z) { + end.z = p_vector.z; + } + + position = begin; + size = end - begin; +} + +void AABB::project_range_in_plane(const Plane &p_plane, real_t &r_min, real_t &r_max) const { + Vector3 half_extents = size * 0.5f; + Vector3 center(position.x + half_extents.x, position.y + half_extents.y, position.z + half_extents.z); + + real_t length = p_plane.normal.abs().dot(half_extents); + real_t distance = p_plane.distance_to(center); + r_min = distance - length; + r_max = distance + length; +} + +inline real_t AABB::get_longest_axis_size() const { + real_t max_size = size.x; + + if (size.y > max_size) { + max_size = size.y; + } + + if (size.z > max_size) { + max_size = size.z; + } + + return max_size; +} + +inline real_t AABB::get_shortest_axis_size() const { + real_t max_size = size.x; + + if (size.y < max_size) { + max_size = size.y; + } + + if (size.z < max_size) { + max_size = size.z; + } + + return max_size; +} + +bool AABB::smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const { + real_t divx = 1 / p_dir.x; + real_t divy = 1 / p_dir.y; + real_t divz = 1 / p_dir.z; + + Vector3 upbound = position + size; + real_t tmin, tmax, tymin, tymax, tzmin, tzmax; + if (p_dir.x >= 0) { + tmin = (position.x - p_from.x) * divx; + tmax = (upbound.x - p_from.x) * divx; + } else { + tmin = (upbound.x - p_from.x) * divx; + tmax = (position.x - p_from.x) * divx; + } + if (p_dir.y >= 0) { + tymin = (position.y - p_from.y) * divy; + tymax = (upbound.y - p_from.y) * divy; + } else { + tymin = (upbound.y - p_from.y) * divy; + tymax = (position.y - p_from.y) * divy; + } + if ((tmin > tymax) || (tymin > tmax)) { + return false; + } + if (tymin > tmin) { + tmin = tymin; + } + if (tymax < tmax) { + tmax = tymax; + } + if (p_dir.z >= 0) { + tzmin = (position.z - p_from.z) * divz; + tzmax = (upbound.z - p_from.z) * divz; + } else { + tzmin = (upbound.z - p_from.z) * divz; + tzmax = (position.z - p_from.z) * divz; + } + if ((tmin > tzmax) || (tzmin > tmax)) { + return false; + } + if (tzmin > tmin) { + tmin = tzmin; + } + if (tzmax < tmax) { + tmax = tzmax; + } + return ((tmin < t1) && (tmax > t0)); +} + +void AABB::grow_by(real_t p_amount) { + position.x -= p_amount; + position.y -= p_amount; + position.z -= p_amount; + size.x += 2 * p_amount; + size.y += 2 * p_amount; + size.z += 2 * p_amount; +} + +void AABB::quantize(real_t p_unit) { + size += position; + + position.x -= Math::fposmodp(position.x, p_unit); + position.y -= Math::fposmodp(position.y, p_unit); + position.z -= Math::fposmodp(position.z, p_unit); + + size.x -= Math::fposmodp(size.x, p_unit); + size.y -= Math::fposmodp(size.y, p_unit); + size.z -= Math::fposmodp(size.z, p_unit); + + size.x += p_unit; + size.y += p_unit; + size.z += p_unit; + + size -= position; +} + +AABB AABB::quantized(real_t p_unit) const { + AABB ret = *this; + ret.quantize(p_unit); + return ret; +} + +#line 0 + +#line 1 "sfw/core/quaternion.h" + +/*************************************************************************/ +/* quaternion.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Quaternion { + union { + struct { + real_t x; + real_t y; + real_t z; + real_t w; + }; + real_t components[4]; + }; + + _FORCE_INLINE_ real_t &operator[](int idx) { + return components[idx]; + } + _FORCE_INLINE_ const real_t &operator[](int idx) const { + return components[idx]; + } + + _FORCE_INLINE_ real_t length_squared() const; + bool is_equal_approx(const Quaternion &p_quat) const; + real_t length() const; + void normalize(); + Quaternion normalized() const; + bool is_normalized() const; + Quaternion inverse() const; + Quaternion log() const; + Quaternion exp() const; + _FORCE_INLINE_ real_t dot(const Quaternion &p_q) const; + real_t angle_to(const Quaternion &p_to) const; + + void set_euler_xyz(const Vector3 &p_euler); + Vector3 get_euler_xyz() const; + void set_euler_yxz(const Vector3 &p_euler); + Vector3 get_euler_yxz() const; + + void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); }; + Vector3 get_euler() const { return get_euler_yxz(); }; + + Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; + Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; + + Vector3 get_axis() const; + float get_angle() const; + + void set_axis_angle(const Vector3 &axis, const real_t &angle); + _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { + r_angle = 2 * Math::acos(w); + real_t r = ((real_t)1) / Math::sqrt(1 - w * w); + r_axis.x = x * r; + r_axis.y = y * r; + r_axis.z = z * r; + } + + void operator*=(const Quaternion &p_q); + Quaternion operator*(const Quaternion &p_q) const; + + Quaternion operator*(const Vector3 &v) const { + return Quaternion(w * v.x + y * v.z - z * v.y, + w * v.y + z * v.x - x * v.z, + w * v.z + x * v.y - y * v.x, + -x * v.x - y * v.y - z * v.z); + } + + _FORCE_INLINE_ Vector3 xform(const Vector3 &v) const { +#ifdef MATH_CHECKS + ERR_FAIL_COND_V_MSG(!is_normalized(), v, "The quaternion must be normalized."); +#endif + Vector3 u(x, y, z); + Vector3 uv = u.cross(v); + return v + ((uv * w) + u.cross(uv)) * ((real_t)2); + } + + _FORCE_INLINE_ void operator+=(const Quaternion &p_q); + _FORCE_INLINE_ void operator-=(const Quaternion &p_q); + _FORCE_INLINE_ void operator*=(const real_t &s); + _FORCE_INLINE_ void operator/=(const real_t &s); + _FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-() const; + _FORCE_INLINE_ Quaternion operator*(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator/(const real_t &s) const; + + _FORCE_INLINE_ bool operator==(const Quaternion &p_quat) const; + _FORCE_INLINE_ bool operator!=(const Quaternion &p_quat) const; + + operator String() const; + + inline void set(real_t p_x, real_t p_y, real_t p_z, real_t p_w) { + x = p_x; + y = p_y; + z = p_z; + w = p_w; + } + inline Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + x(p_x), + y(p_y), + z(p_z), + w(p_w) { + } + Quaternion(const Vector3 &axis, const real_t &angle) { + set_axis_angle(axis, angle); + } + + Quaternion(const Vector3 &euler) { + set_euler(euler); + } + Quaternion(const Quaternion &p_q) : + x(p_q.x), + y(p_q.y), + z(p_q.z), + w(p_q.w) { + } + + Quaternion &operator=(const Quaternion &p_q) { + x = p_q.x; + y = p_q.y; + z = p_q.z; + w = p_q.w; + return *this; + } + + Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc + { + Vector3 c = v0.cross(v1); + real_t d = v0.dot(v1); + + if (d < -1 + (real_t)CMP_EPSILON) { + x = 0; + y = 1; + z = 0; + w = 0; + } else { + real_t s = Math::sqrt((1 + d) * 2); + real_t rs = 1 / s; + + x = c.x * rs; + y = c.y * rs; + z = c.z * rs; + w = s * 0.5f; + } + } + + inline Quaternion() : + x(0), + y(0), + z(0), + w(1) { + } +}; + +real_t Quaternion::dot(const Quaternion &p_q) const { + return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w; +} + +real_t Quaternion::length_squared() const { + return dot(*this); +} + +void Quaternion::operator+=(const Quaternion &p_q) { + x += p_q.x; + y += p_q.y; + z += p_q.z; + w += p_q.w; +} + +void Quaternion::operator-=(const Quaternion &p_q) { + x -= p_q.x; + y -= p_q.y; + z -= p_q.z; + w -= p_q.w; +} + +void Quaternion::operator*=(const real_t &s) { + x *= s; + y *= s; + z *= s; + w *= s; +} + +void Quaternion::operator/=(const real_t &s) { + *this *= 1 / s; +} + +Quaternion Quaternion::operator+(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); +} + +Quaternion Quaternion::operator-(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); +} + +Quaternion Quaternion::operator-() const { + const Quaternion &q2 = *this; + return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w); +} + +Quaternion Quaternion::operator*(const real_t &s) const { + return Quaternion(x * s, y * s, z * s, w * s); +} + +Quaternion Quaternion::operator/(const real_t &s) const { + return *this * (1 / s); +} + +bool Quaternion::operator==(const Quaternion &p_quat) const { + return x == p_quat.x && y == p_quat.y && z == p_quat.z && w == p_quat.w; +} + +bool Quaternion::operator!=(const Quaternion &p_quat) const { + return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w; +} + +#line 0 + +#line 1 "sfw/core/projection.h" + +/*************************************************************************/ +/* projection.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct AABB; +struct Plane; +struct Rect2; +struct Transform; +struct Vector2; + +struct _NO_DISCARD_CLASS_ Projection { + enum Planes { + PLANE_NEAR, + PLANE_FAR, + PLANE_LEFT, + PLANE_TOP, + PLANE_RIGHT, + PLANE_BOTTOM + }; + + Vector4 matrix[4]; + + _FORCE_INLINE_ const Vector4 &operator[](const int p_axis) const { + DEV_ASSERT((unsigned int)p_axis < 4); + return matrix[p_axis]; + } + + _FORCE_INLINE_ Vector4 &operator[](const int p_axis) { + DEV_ASSERT((unsigned int)p_axis < 4); + return matrix[p_axis]; + } + + float determinant() const; + void set_identity(); + void set_zero(); + void set_light_bias(); + void set_depth_correction(bool p_flip_y = true); + + void set_light_atlas_rect(const Rect2 &p_rect); + void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); + void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); + void 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); + void set_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); + void set_orthogonal(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); + void set_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far); + void set_frustum(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); + void adjust_perspective_znear(real_t p_new_znear); + + static Projection create_depth_correction(bool p_flip_y); + static Projection create_light_atlas_rect(const Rect2 &p_rect); + static Projection create_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); + static Projection create_perspective_hmd(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist); + static Projection create_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); + static Projection create_orthogonal(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar); + static Projection create_orthogonal_aspect(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false); + static Projection create_frustum(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far); + static Projection create_frustum_aspect(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); + static Projection create_fit_aabb(const AABB &p_aabb); + + Projection perspective_znear_adjusted(real_t p_new_znear) const; + Plane get_projection_plane(Planes p_plane) const; + Projection flipped_y() const; + Projection jitter_offseted(const Vector2 &p_offset) const; + + static real_t get_fovy(real_t p_fovx, real_t p_aspect) { + return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0); + } + + real_t calculate_fovy(real_t p_fovx, real_t p_aspect) { + return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0); + } + + real_t get_z_far() const; + real_t get_z_near() const; + real_t get_aspect() const; + real_t get_fov() const; + bool is_orthogonal() const; + + Vector get_projection_planes(const Transform &p_transform) const; + + bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const; + Vector2 get_viewport_half_extents() const; + Vector2 get_far_plane_half_extents() const; + + void invert(); + Projection inverse() const; + + Projection operator*(const Projection &p_matrix) const; + + Vector4 xform(const Vector4 &p_vec4) const; + Vector4 xform_inv(const Vector4 &p_vec4) const; + + _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; + Plane xform(const Plane &p_plane) const; + + operator String() const; + + void scale_translate_to_fit(const AABB &p_aabb); + void add_jitter_offset(const Vector2 &p_offset); + void make_scale(const Vector3 &p_scale); + int get_pixels_per_meter(int p_for_pixel_width) const; + operator Transform() const; + + void flip_y(); + + bool operator==(const Projection &p_cam) const { + for (uint32_t i = 0; i < 4; i++) { + for (uint32_t j = 0; j < 4; j++) { + if (matrix[i][j] != p_cam.matrix[i][j]) { + return false; + } + } + } + return true; + } + + bool operator!=(const Projection &p_cam) const { + return !(*this == p_cam); + } + + float get_lod_multiplier() const; + + _FORCE_INLINE_ void set_perspective1(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false) { + set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov); + } + _FORCE_INLINE_ void set_perspective2(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov, int p_eye, real_t p_intraocular_dist, real_t p_convergence_dist) { + set_perspective(p_fovy_degrees, p_aspect, p_z_near, p_z_far, p_flip_fov, p_eye, p_intraocular_dist, p_convergence_dist); + } + _FORCE_INLINE_ void set_orthogonal1(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_znear, real_t p_zfar) { + set_orthogonal(p_left, p_right, p_bottom, p_top, p_znear, p_zfar); + } + _FORCE_INLINE_ void set_orthogonal2(real_t p_size, real_t p_aspect, real_t p_znear, real_t p_zfar, bool p_flip_fov = false) { + set_orthogonal(p_size, p_aspect, p_znear, p_zfar, p_flip_fov); + } + _FORCE_INLINE_ void set_frustum1(real_t p_left, real_t p_right, real_t p_bottom, real_t p_top, real_t p_near, real_t p_far) { + set_frustum(p_left, p_right, p_bottom, p_top, p_near, p_far); + } + //Vector2 is incomplete here + void set_frustum2(real_t p_size, real_t p_aspect, Vector2 p_offset, real_t p_near, real_t p_far, bool p_flip_fov = false); + + Projection(); + Projection(const Vector4 &p_x, const Vector4 &p_y, const Vector4 &p_z, const Vector4 &p_w); + Projection(const Transform &p_transform); + ~Projection(); +}; + +Vector3 Projection::xform(const Vector3 &p_vec3) const { + Vector3 ret; + ret.x = matrix[0][0] * p_vec3.x + matrix[1][0] * p_vec3.y + matrix[2][0] * p_vec3.z + matrix[3][0]; + ret.y = matrix[0][1] * p_vec3.x + matrix[1][1] * p_vec3.y + matrix[2][1] * p_vec3.z + matrix[3][1]; + ret.z = matrix[0][2] * p_vec3.x + matrix[1][2] * p_vec3.y + matrix[2][2] * p_vec3.z + matrix[3][2]; + real_t w = matrix[0][3] * p_vec3.x + matrix[1][3] * p_vec3.y + matrix[2][3] * p_vec3.z + matrix[3][3]; + return ret / w; +} + +#line 0 + +#line 1 "sfw/core/basis.h" + +/*************************************************************************/ +/* basis.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Basis { + Vector3 rows[3] = { + Vector3(1, 0, 0), + Vector3(0, 1, 0), + Vector3(0, 0, 1) + }; + + _FORCE_INLINE_ const Vector3 &operator[](int p_row) const { + return rows[p_row]; + } + _FORCE_INLINE_ Vector3 &operator[](int p_row) { + return rows[p_row]; + } + + void invert(); + void transpose(); + + Basis inverse() const; + Basis transposed() const; + + _FORCE_INLINE_ real_t determinant() const; + + void from_z(const Vector3 &p_z); + + void rotate(const Vector3 &p_axis, real_t p_phi); + Basis rotated(const Vector3 &p_axis, real_t p_phi) const; + + void rotate_local(const Vector3 &p_axis, real_t p_phi); + Basis rotated_local(const Vector3 &p_axis, real_t p_phi) const; + + void rotate(const Vector3 &p_euler); + Basis rotated(const Vector3 &p_euler) const; + + void rotate(const Quaternion &p_quat); + Basis rotated(const Quaternion &p_quat) const; + + _FORCE_INLINE_ void rotatev(const Vector3 &p_euler) { rotate(p_euler); } + _FORCE_INLINE_ Basis rotatedv(const Vector3 &p_euler) const { return rotated(p_euler); } + _FORCE_INLINE_ void rotateq(const Quaternion &p_quat) { rotate(p_quat); } + _FORCE_INLINE_ Basis rotatedq(const Quaternion &p_quat) const { return rotated(p_quat); } + + Vector3 get_rotation_euler() const; + void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; + void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; + Quaternion get_rotation_quaternion() const; + Vector3 get_rotation() const { return get_rotation_euler(); }; + + void rotate_to_align(const Vector3 &p_start_direction, const Vector3 &p_end_direction); + + Vector3 rotref_posscale_decomposition(Basis &rotref) const; + + Vector3 get_euler_xyz() const; + void set_euler_xyz(const Vector3 &p_euler); + + Vector3 get_euler_xzy() const; + void set_euler_xzy(const Vector3 &p_euler); + + Vector3 get_euler_yzx() const; + void set_euler_yzx(const Vector3 &p_euler); + + Vector3 get_euler_yxz() const; + void set_euler_yxz(const Vector3 &p_euler); + + Vector3 get_euler_zxy() const; + void set_euler_zxy(const Vector3 &p_euler); + + Vector3 get_euler_zyx() const; + void set_euler_zyx(const Vector3 &p_euler); + + Vector3 get_euler() const { return get_euler_yxz(); } + void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); } + + Quaternion get_quaternion() const; + void set_quaternion(const Quaternion &p_quat); + + void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const; + void set_axis_angle(const Vector3 &p_axis, real_t p_phi); + + void scale(const Vector3 &p_scale); + Basis scaled(const Vector3 &p_scale) const; + + void scale_local(const Vector3 &p_scale); + Basis scaled_local(const Vector3 &p_scale) const; + + void scale_orthogonal(const Vector3 &p_scale); + Basis scaled_orthogonal(const Vector3 &p_scale) const; + + void make_scale_uniform(); + real_t get_uniform_scale() const; + + Vector3 get_scale() const; + Vector3 get_scale_abs() const; + Vector3 get_scale_local() const; + + void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale); + void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale); + void set_quaternion_scale(const Quaternion &p_quat, const Vector3 &p_scale); + + // transposed dot products + _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { + return rows[0][0] * v[0] + rows[1][0] * v[1] + rows[2][0] * v[2]; + } + _FORCE_INLINE_ real_t tdoty(const Vector3 &v) const { + return rows[0][1] * v[0] + rows[1][1] * v[1] + rows[2][1] * v[2]; + } + _FORCE_INLINE_ real_t tdotz(const Vector3 &v) const { + return rows[0][2] * v[0] + rows[1][2] * v[1] + rows[2][2] * v[2]; + } + + bool is_equal_approx(const Basis &p_basis) const; + bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon = UNIT_EPSILON) const; + + bool operator==(const Basis &p_matrix) const; + bool operator!=(const Basis &p_matrix) const; + + _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; + _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; + + _FORCE_INLINE_ Vector3i xform(const Vector3i &p_vector) const; + _FORCE_INLINE_ Vector3i xform_inv(const Vector3i &p_vector) const; + + _FORCE_INLINE_ void operator*=(const Basis &p_matrix); + _FORCE_INLINE_ Basis operator*(const Basis &p_matrix) const; + _FORCE_INLINE_ void operator+=(const Basis &p_matrix); + _FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const; + _FORCE_INLINE_ void operator-=(const Basis &p_matrix); + _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; + _FORCE_INLINE_ void operator*=(real_t p_val); + _FORCE_INLINE_ Basis operator*(real_t p_val) const; + + int get_orthogonal_index() const; + void set_orthogonal_index(int p_index); + + void set_diagonal(const Vector3 &p_diag); + + bool is_orthogonal() const; + bool is_diagonal() const; + bool is_rotation() const; + + Basis slerp(const Basis &p_to, const real_t &p_weight) const; + _FORCE_INLINE_ Basis lerp(const Basis &p_to, const real_t &p_weight) const; + void rotate_sh(real_t *p_values); + + operator String() const; + + /* create / set */ + + _FORCE_INLINE_ void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { + rows[0][0] = xx; + rows[0][1] = xy; + rows[0][2] = xz; + rows[1][0] = yx; + rows[1][1] = yy; + rows[1][2] = yz; + rows[2][0] = zx; + rows[2][1] = zy; + rows[2][2] = zz; + } + _FORCE_INLINE_ void set(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) { + set_column(0, p_x); + set_column(1, p_y); + set_column(2, p_z); + } + + _FORCE_INLINE_ Vector3 get_column(int i) const { + return Vector3(rows[0][i], rows[1][i], rows[2][i]); + } + + _FORCE_INLINE_ void set_column(int p_index, const Vector3 &p_value) { + // Set actual basis axis column (we store transposed as rows for performance). + rows[0][p_index] = p_value.x; + rows[1][p_index] = p_value.y; + rows[2][p_index] = p_value.z; + } + + _FORCE_INLINE_ void set_columns(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z) { + set_column(0, p_x); + set_column(1, p_y); + set_column(2, p_z); + } + + _FORCE_INLINE_ Vector3 get_row(int i) const { + return Vector3(rows[i][0], rows[i][1], rows[i][2]); + } + _FORCE_INLINE_ void set_row(int i, const Vector3 &p_row) { + rows[i][0] = p_row.x; + rows[i][1] = p_row.y; + rows[i][2] = p_row.z; + } + + _FORCE_INLINE_ Vector3 get_axis(int i) const { + return Vector3(rows[0][i], rows[1][i], rows[2][i]); + } + + _FORCE_INLINE_ void set_axis(int p_index, const Vector3 &p_value) { + // Set actual basis axis column (we store transposed as rows for performance). + rows[0][p_index] = p_value.x; + rows[1][p_index] = p_value.y; + rows[2][p_index] = p_value.z; + } + + _FORCE_INLINE_ Vector3 get_main_diagonal() const { + return Vector3(rows[0][0], rows[1][1], rows[2][2]); + } + + _FORCE_INLINE_ void set_zero() { + rows[0].zero(); + rows[1].zero(); + rows[2].zero(); + } + + _FORCE_INLINE_ Basis transpose_xform(const Basis &m) const { + return Basis( + rows[0].x * m[0].x + rows[1].x * m[1].x + rows[2].x * m[2].x, + rows[0].x * m[0].y + rows[1].x * m[1].y + rows[2].x * m[2].y, + rows[0].x * m[0].z + rows[1].x * m[1].z + rows[2].x * m[2].z, + rows[0].y * m[0].x + rows[1].y * m[1].x + rows[2].y * m[2].x, + rows[0].y * m[0].y + rows[1].y * m[1].y + rows[2].y * m[2].y, + rows[0].y * m[0].z + rows[1].y * m[1].z + rows[2].y * m[2].z, + rows[0].z * m[0].x + rows[1].z * m[1].x + rows[2].z * m[2].x, + rows[0].z * m[0].y + rows[1].z * m[1].y + rows[2].z * m[2].y, + rows[0].z * m[0].z + rows[1].z * m[1].z + rows[2].z * m[2].z); + } + Basis(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz) { + set(xx, xy, xz, yx, yy, yz, zx, zy, zz); + } + + void orthonormalize(); + Basis orthonormalized() const; + + void orthogonalize(); + Basis orthogonalized() const; + + bool is_symmetric() const; + Basis diagonalize(); + + // The following normal xform functions are correct for non-uniform scales. + // Use these two functions in combination to xform a series of normals. + // First use get_normal_xform_basis() to precalculate the inverse transpose. + // Then apply xform_normal_fast() multiple times using the inverse transpose basis. + Basis get_normal_xform_basis() const { return inverse().transposed(); } + + // N.B. This only does a normal transform if the basis used is the inverse transpose! + // Otherwise use xform_normal(). + Vector3 xform_normal_fast(const Vector3 &p_vector) const { return xform(p_vector).normalized(); } + + // This function does the above but for a single normal vector. It is considerably slower, so should usually + // only be used in cases of single normals, or when the basis changes each time. + Vector3 xform_normal(const Vector3 &p_vector) const { return get_normal_xform_basis().xform_normal_fast(p_vector); } + + static Basis looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + static Basis from_scale(const Vector3 &p_scale); + + operator Quaternion() const { return get_quaternion(); } + + Basis(const Quaternion &p_quat) { set_quaternion(p_quat); } + Basis(const Quaternion &p_quat, const Vector3 &p_scale) { set_quaternion_scale(p_quat, p_scale); } + + Basis(const Vector3 &p_euler) { set_euler(p_euler); } + Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); } + + Basis(const Vector3 &p_axis, real_t p_phi) { set_axis_angle(p_axis, p_phi); } + Basis(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale) { set_axis_angle_scale(p_axis, p_phi, p_scale); } + + _FORCE_INLINE_ Basis(const Vector3 &row0, const Vector3 &row1, const Vector3 &row2) { + rows[0] = row0; + rows[1] = row1; + rows[2] = row2; + } + + _FORCE_INLINE_ Basis() {} +}; + +_FORCE_INLINE_ void Basis::operator*=(const Basis &p_matrix) { + set( + p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]), + p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]), + p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2])); +} + +_FORCE_INLINE_ Basis Basis::operator*(const Basis &p_matrix) const { + return Basis( + p_matrix.tdotx(rows[0]), p_matrix.tdoty(rows[0]), p_matrix.tdotz(rows[0]), + p_matrix.tdotx(rows[1]), p_matrix.tdoty(rows[1]), p_matrix.tdotz(rows[1]), + p_matrix.tdotx(rows[2]), p_matrix.tdoty(rows[2]), p_matrix.tdotz(rows[2])); +} + +_FORCE_INLINE_ void Basis::operator+=(const Basis &p_matrix) { + rows[0] += p_matrix.rows[0]; + rows[1] += p_matrix.rows[1]; + rows[2] += p_matrix.rows[2]; +} + +_FORCE_INLINE_ Basis Basis::operator+(const Basis &p_matrix) const { + Basis ret(*this); + ret += p_matrix; + return ret; +} + +_FORCE_INLINE_ void Basis::operator-=(const Basis &p_matrix) { + rows[0] -= p_matrix.rows[0]; + rows[1] -= p_matrix.rows[1]; + rows[2] -= p_matrix.rows[2]; +} + +_FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { + Basis ret(*this); + ret -= p_matrix; + return ret; +} + +_FORCE_INLINE_ void Basis::operator*=(real_t p_val) { + rows[0] *= p_val; + rows[1] *= p_val; + rows[2] *= p_val; +} + +_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const { + Basis ret(*this); + ret *= p_val; + return ret; +} + +Vector3 Basis::xform(const Vector3 &p_vector) const { + return Vector3( + rows[0].dot(p_vector), + rows[1].dot(p_vector), + rows[2].dot(p_vector)); +} + +Vector3i Basis::xform_inv(const Vector3i &p_vector) const { + return Vector3i( + (rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z), + (rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z), + (rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z)); +} + +Vector3i Basis::xform(const Vector3i &p_vector) const { + return Vector3i( + rows[0].dot(p_vector), + rows[1].dot(p_vector), + rows[2].dot(p_vector)); +} + +Vector3 Basis::xform_inv(const Vector3 &p_vector) const { + return Vector3( + (rows[0][0] * p_vector.x) + (rows[1][0] * p_vector.y) + (rows[2][0] * p_vector.z), + (rows[0][1] * p_vector.x) + (rows[1][1] * p_vector.y) + (rows[2][1] * p_vector.z), + (rows[0][2] * p_vector.x) + (rows[1][2] * p_vector.y) + (rows[2][2] * p_vector.z)); +} + +real_t Basis::determinant() const { + return rows[0][0] * (rows[1][1] * rows[2][2] - rows[2][1] * rows[1][2]) - + rows[1][0] * (rows[0][1] * rows[2][2] - rows[2][1] * rows[0][2]) + + rows[2][0] * (rows[0][1] * rows[1][2] - rows[1][1] * rows[0][2]); +} + +Basis Basis::lerp(const Basis &p_to, const real_t &p_weight) const { + Basis b; + b.rows[0] = rows[0].linear_interpolate(p_to.rows[0], p_weight); + b.rows[1] = rows[1].linear_interpolate(p_to.rows[1], p_weight); + b.rows[2] = rows[2].linear_interpolate(p_to.rows[2], p_weight); + + return b; +} + +#line 0 + +#line 1 "sfw/core/transform_2d.h" + +/*************************************************************************/ +/* transform_2d.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Transform2D { + // Warning #1: basis of Transform2D is stored differently from Basis. In terms of columns array, the basis matrix looks like "on paper": + // M = (columns[0][0] columns[1][0]) + // (columns[0][1] columns[1][1]) + // This is such that the columns, which can be interpreted as basis vectors of the coordinate system "painted" on the object, can be accessed as columns[i]. + // Note that this is the opposite of the indices in mathematical texts, meaning: $M_{12}$ in a math book corresponds to columns[1][0] here. + // This requires additional care when working with explicit indices. + // See https://en.wikipedia.org/wiki/Row-_and_column-major_order for further reading. + + // Warning #2: 2D be aware that unlike 3D code, 2D code uses a left-handed coordinate system: Y-axis points down, + // and angle is measure from +X to +Y in a clockwise-fashion. + + Vector2 columns[3]; + + _FORCE_INLINE_ real_t tdotx(const Vector2 &v) const { return columns[0][0] * v.x + columns[1][0] * v.y; } + _FORCE_INLINE_ real_t tdoty(const Vector2 &v) const { return columns[0][1] * v.x + columns[1][1] * v.y; } + + const Vector2 &operator[](int p_idx) const { return columns[p_idx]; } + Vector2 &operator[](int p_idx) { return columns[p_idx]; } + + _FORCE_INLINE_ Vector2 get_axis(int p_axis) const { + ERR_FAIL_INDEX_V(p_axis, 3, Vector2()); + return columns[p_axis]; + } + _FORCE_INLINE_ void set_axis(int p_axis, const Vector2 &p_vec) { + ERR_FAIL_INDEX(p_axis, 3); + columns[p_axis] = p_vec; + } + + _FORCE_INLINE_ Vector2 get_column(int p_colum) const { + ERR_FAIL_INDEX_V(p_colum, 3, Vector2()); + return columns[p_colum]; + } + _FORCE_INLINE_ void set_column(int p_colum, const Vector2 &p_vec) { + ERR_FAIL_INDEX(p_colum, 3); + columns[p_colum] = p_vec; + } + + void invert(); + Transform2D inverse() const; + + void affine_invert(); + Transform2D affine_inverse() const; + + void set_rotation(real_t p_rot); + real_t get_rotation() const; + real_t get_skew() const; + void set_skew(const real_t p_angle); + _FORCE_INLINE_ void set_rotation_and_scale(real_t p_rot, const Size2 &p_scale); + _FORCE_INLINE_ void set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew); + void rotate(real_t p_phi); + + void scale(const Size2 &p_scale); + void scale_basis(const Size2 &p_scale); + void translate(real_t p_tx, real_t p_ty); + void translate(const Vector2 &p_offset); + void translate_local(real_t p_tx, real_t p_ty); + void translate_local(const Vector2 &p_translation); + + void translater(real_t p_tx, real_t p_ty); + void translatev(const Vector2 &p_offset); + void translate_localr(real_t p_tx, real_t p_ty); + void translate_localv(const Vector2 &p_translation); + + real_t basis_determinant() const; + + Size2 get_scale() const; + void set_scale(const Size2 &p_scale); + + _FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; } + _FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; } + + Transform2D basis_scaled(const Size2 &p_scale) const; + Transform2D scaled(const Size2 &p_scale) const; + Transform2D scaled_local(const Size2 &p_scale) const; + Transform2D translated(const Vector2 &p_offset) const; + Transform2D translated_local(const Vector2 &p_offset) const; + Transform2D rotated(const real_t p_angle) const; + Transform2D rotated_local(const real_t p_angle) const; + + Transform2D untranslated() const; + + void orthonormalize(); + Transform2D orthonormalized() const; + bool is_equal_approx(const Transform2D &p_transform) const; + + Transform2D looking_at(const Vector2 &p_target) const; + + bool operator==(const Transform2D &p_transform) const; + bool operator!=(const Transform2D &p_transform) const; + + void operator*=(const Transform2D &p_transform); + Transform2D operator*(const Transform2D &p_transform) const; + void operator*=(const real_t p_val); + Transform2D operator*(const real_t p_val) const; + + Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; + + _FORCE_INLINE_ Vector2 basis_xform(const Vector2 &p_vec) const; + _FORCE_INLINE_ Vector2 basis_xform_inv(const Vector2 &p_vec) const; + _FORCE_INLINE_ Vector2 xform(const Vector2 &p_vec) const; + _FORCE_INLINE_ Vector2 xform_inv(const Vector2 &p_vec) const; + + _FORCE_INLINE_ Rect2 xform(const Rect2 &p_rect) const; + _FORCE_INLINE_ Rect2 xform_inv(const Rect2 &p_rect) const; + + _FORCE_INLINE_ Vector2i basis_xform(const Vector2i &p_vec) const; + _FORCE_INLINE_ Vector2i basis_xform_inv(const Vector2i &p_vec) const; + _FORCE_INLINE_ Vector2i xform(const Vector2i &p_vec) const; + _FORCE_INLINE_ Vector2i xform_inv(const Vector2i &p_vec) const; + + _FORCE_INLINE_ PoolVector xform(const PoolVector &p_array) const; + _FORCE_INLINE_ PoolVector xform_inv(const PoolVector &p_array) const; + _FORCE_INLINE_ PoolVector xform(const PoolVector &p_array) const; + _FORCE_INLINE_ PoolVector xform_inv(const PoolVector &p_array) const; + + operator String() const; + + Transform2D(real_t xx, real_t xy, real_t yx, real_t yy, real_t ox, real_t oy) { + columns[0][0] = xx; + columns[0][1] = xy; + columns[1][0] = yx; + columns[1][1] = yy; + columns[2][0] = ox; + columns[2][1] = oy; + } + + Transform2D(const Vector2 &p_x, const Vector2 &p_y, const Vector2 &p_origin) { + columns[0] = p_x; + columns[1] = p_y; + columns[2] = p_origin; + } + + Transform2D(real_t p_rot, const Vector2 &p_pos); + + Transform2D(const real_t p_rot, const Size2 &p_scale, const real_t p_skew, const Vector2 &p_pos); + + Transform2D() { + columns[0][0] = 1.0; + columns[1][1] = 1.0; + } +}; + +Vector2 Transform2D::basis_xform(const Vector2 &p_vec) const { + return Vector2( + tdotx(p_vec), + tdoty(p_vec)); +} + +Vector2 Transform2D::basis_xform_inv(const Vector2 &p_vec) const { + return Vector2( + columns[0].dot(p_vec), + columns[1].dot(p_vec)); +} + +Vector2 Transform2D::xform(const Vector2 &p_vec) const { + return Vector2( + tdotx(p_vec), + tdoty(p_vec)) + + columns[2]; +} +Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const { + Vector2 v = p_vec - columns[2]; + + return Vector2( + columns[0].dot(v), + columns[1].dot(v)); +} +Rect2 Transform2D::xform(const Rect2 &p_rect) const { + Vector2 x = columns[0] * p_rect.size.x; + Vector2 y = columns[1] * p_rect.size.y; + Vector2 pos = xform(p_rect.position); + + Rect2 new_rect; + new_rect.position = pos; + new_rect.expand_to(pos + x); + new_rect.expand_to(pos + y); + new_rect.expand_to(pos + x + y); + return new_rect; +} + +void Transform2D::set_rotation_and_scale(real_t p_rot, const Size2 &p_scale) { + columns[0][0] = Math::cos(p_rot) * p_scale.x; + columns[1][1] = Math::cos(p_rot) * p_scale.y; + columns[1][0] = -Math::sin(p_rot) * p_scale.y; + columns[0][1] = Math::sin(p_rot) * p_scale.x; +} + +void Transform2D::set_rotation_scale_and_skew(const real_t p_rot, const Size2 &p_scale, const real_t p_skew) { + columns[0][0] = Math::cos(p_rot) * p_scale.x; + columns[1][1] = Math::cos(p_rot + p_skew) * p_scale.y; + columns[1][0] = -Math::sin(p_rot + p_skew) * p_scale.y; + columns[0][1] = Math::sin(p_rot) * p_scale.x; +} + +Rect2 Transform2D::xform_inv(const Rect2 &p_rect) const { + Vector2 ends[4] = { + xform_inv(p_rect.position), + xform_inv(Vector2(p_rect.position.x, p_rect.position.y + p_rect.size.y)), + xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y + p_rect.size.y)), + xform_inv(Vector2(p_rect.position.x + p_rect.size.x, p_rect.position.y)) + }; + + Rect2 new_rect; + new_rect.position = ends[0]; + new_rect.expand_to(ends[1]); + new_rect.expand_to(ends[2]); + new_rect.expand_to(ends[3]); + + return new_rect; +} + +Vector2i Transform2D::basis_xform(const Vector2i &p_vec) const { + return Vector2i( + tdotx(p_vec), + tdoty(p_vec)); +} + +Vector2i Transform2D::basis_xform_inv(const Vector2i &p_vec) const { + return Vector2i( + columns[0].dot(p_vec), + columns[1].dot(p_vec)); +} + +Vector2i Transform2D::xform(const Vector2i &p_vec) const { + return Vector2i( + tdotx(p_vec), + tdoty(p_vec)) + + columns[2]; +} +Vector2i Transform2D::xform_inv(const Vector2i &p_vec) const { + Vector2i v = p_vec - columns[2]; + + return Vector2i( + columns[0].dot(v), + columns[1].dot(v)); +} + +PoolVector Transform2D::xform(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform(r[i]); + } + return array; +} + +PoolVector Transform2D::xform_inv(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform_inv(r[i]); + } + return array; +} + +PoolVector Transform2D::xform(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform(r[i]); + } + return array; +} + +PoolVector Transform2D::xform_inv(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform_inv(r[i]); + } + return array; +} + +#line 0 + +#line 1 "sfw/core/face3.h" + +/*************************************************************************/ +/* face3.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Face3 { + enum Side { + SIDE_OVER, + SIDE_UNDER, + SIDE_SPANNING, + SIDE_COPLANAR + }; + + Vector3 vertex[3]; + + /** + * + * @param p_plane plane used to split the face + * @param p_res array of at least 3 faces, amount used in function return + * @param p_is_point_over array of at least 3 booleans, determining which face is over the plane, amount used in function return + * @param _epsilon constant used for numerical error rounding, to add "thickness" to the plane (so coplanar points can happen) + * @return amount of faces generated by the split, either 0 (means no split possible), 2 or 3 + */ + + int split_by_plane(const Plane &p_plane, Face3 *p_res, bool *p_is_point_over) const; + + Plane get_plane(ClockDirection p_dir = CLOCKWISE) const; + Vector3 get_random_point_inside() const; + + Side get_side_of(const Face3 &p_face, ClockDirection p_clock_dir = CLOCKWISE) const; + + bool is_degenerate() const; + real_t get_area() const; + real_t get_twice_area_squared() const; + + Vector3 get_median_point() const; + Vector3 get_closest_point_to(const Vector3 &p_point) const; + + bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const; + bool intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const; + + ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity + + void get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; + void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + + AABB get_aabb() const { + AABB aabb(vertex[0], Vector3()); + aabb.expand_to(vertex[1]); + aabb.expand_to(vertex[2]); + return aabb; + } + + bool intersects_aabb(const AABB &p_aabb) const; + _FORCE_INLINE_ bool intersects_aabb2(const AABB &p_aabb) const; + operator String() const; + + inline Face3() {} + inline Face3(const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) { + vertex[0] = p_v1; + vertex[1] = p_v2; + vertex[2] = p_v3; + } +}; + +inline real_t Face3::get_twice_area_squared() const { + Vector3 edge1 = vertex[1] - vertex[0]; + Vector3 edge2 = vertex[2] - vertex[0]; + return edge1.cross(edge2).length_squared(); +} + +bool Face3::intersects_aabb2(const AABB &p_aabb) const { + Vector3 perp = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]); + + Vector3 half_extents = p_aabb.size * 0.5f; + Vector3 ofs = p_aabb.position + half_extents; + + Vector3 sup = Vector3( + (perp.x > 0) ? -half_extents.x : half_extents.x, + (perp.y > 0) ? -half_extents.y : half_extents.y, + (perp.z > 0) ? -half_extents.z : half_extents.z); + + real_t d = perp.dot(vertex[0]); + real_t dist_a = perp.dot(ofs + sup) - d; + real_t dist_b = perp.dot(ofs - sup) - d; + + if (dist_a * dist_b > 0) { + return false; //does not intersect the plane + } + +#define TEST_AXIS(m_ax) \ + { \ + real_t aabb_min = p_aabb.position.m_ax; \ + real_t aabb_max = p_aabb.position.m_ax + p_aabb.size.m_ax; \ + real_t tri_min, tri_max; \ + for (int i = 0; i < 3; i++) { \ + if (i == 0 || vertex[i].m_ax > tri_max) \ + tri_max = vertex[i].m_ax; \ + if (i == 0 || vertex[i].m_ax < tri_min) \ + tri_min = vertex[i].m_ax; \ + } \ + \ + if (tri_max < aabb_min || aabb_max < tri_min) \ + return false; \ + } + + TEST_AXIS(x); + TEST_AXIS(y); + TEST_AXIS(z); + +#undef TEST_AXIS + + Vector3 edge_norms[3] = { + vertex[0] - vertex[1], + vertex[1] - vertex[2], + vertex[2] - vertex[0], + }; + + for (int i = 0; i < 12; i++) { + Vector3 from, to; + switch (i) { + case 0: { + from = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z); + to = Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z); + } break; + case 1: { + from = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z); + to = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z); + } break; + case 2: { + from = Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z); + to = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z); + + } break; + case 3: { + from = Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z); + to = Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z); + + } break; + case 4: { + from = Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z); + to = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z); + } break; + case 5: { + from = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z); + to = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z); + } break; + case 6: { + from = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z); + to = Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z); + + } break; + case 7: { + from = Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z); + to = Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z); + + } break; + case 8: { + from = Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z); + to = Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z); + + } break; + case 9: { + from = Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z); + to = Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z); + + } break; + case 10: { + from = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z); + to = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z); + + } break; + case 11: { + from = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z); + to = Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z); + + } break; + } + + Vector3 e1 = from - to; + for (int j = 0; j < 3; j++) { + Vector3 e2 = edge_norms[j]; + + Vector3 axis = vec3_cross(e1, e2); + + if (axis.length_squared() < 0.0001f) { + continue; // coplanar + } + //axis.normalize(); + + Vector3 sup2 = Vector3( + (axis.x > 0) ? -half_extents.x : half_extents.x, + (axis.y > 0) ? -half_extents.y : half_extents.y, + (axis.z > 0) ? -half_extents.z : half_extents.z); + + real_t maxB = axis.dot(ofs + sup2); + real_t minB = axis.dot(ofs - sup2); + if (minB > maxB) { + SWAP(maxB, minB); + } + + real_t minT = 1e20, maxT = -1e20; + for (int k = 0; k < 3; k++) { + real_t vert_d = axis.dot(vertex[k]); + + if (vert_d > maxT) { + maxT = vert_d; + } + + if (vert_d < minT) { + minT = vert_d; + } + } + + if (maxB < minT || maxT < minB) { + return false; + } + } + } + return true; +} + +#line 0 + +#line 1 "sfw/core/transform.h" + +/*************************************************************************/ +/* transform.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +struct _NO_DISCARD_CLASS_ Transform { + Basis basis; + Vector3 origin; + + void invert(); + Transform inverse() const; + + void affine_invert(); + Transform affine_inverse() const; + + Transform rotated(const Vector3 &p_axis, real_t p_phi) const; + Transform rotated_local(const Vector3 &p_axis, real_t p_phi) const; + + void rotate(const Vector3 &p_axis, real_t p_phi); + void rotate_local(const Vector3 &p_axis, real_t p_phi); + void rotate_basis(const Vector3 &p_axis, real_t p_phi); + + void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up); + Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const; + + void scale(const Vector3 &p_scale); + Transform scaled(const Vector3 &p_scale) const; + Transform scaled_local(const Vector3 &p_scale) const; + void scale_basis(const Vector3 &p_scale); + + void translate_local(real_t p_tx, real_t p_ty, real_t p_tz); + void translate_local(const Vector3 &p_translation); + void translate_localr(real_t p_tx, real_t p_ty, real_t p_tz); + void translate_localv(const Vector3 &p_translation); + Transform translated(const Vector3 &p_translation) const; + Transform translated_local(const Vector3 &p_translation) const; + + const Basis &get_basis() const { return basis; } + void set_basis(const Basis &p_basis) { basis = p_basis; } + + const Vector3 &get_origin() const { return origin; } + void set_origin(const Vector3 &p_origin) { origin = p_origin; } + + void orthonormalize(); + Transform orthonormalized() const; + void orthogonalize(); + Transform orthogonalized() const; + bool is_equal_approx(const Transform &p_transform) const; + + bool operator==(const Transform &p_transform) const; + bool operator!=(const Transform &p_transform) const; + + _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; + _FORCE_INLINE_ Vector3i xform(const Vector3i &p_vector) const; + _FORCE_INLINE_ AABB xform(const AABB &p_aabb) const; + _FORCE_INLINE_ PoolVector xform(const PoolVector &p_array) const; + _FORCE_INLINE_ PoolVector xform(const PoolVector &p_array) const; + + // NOTE: These are UNSAFE with non-uniform scaling, and will produce incorrect results. + // They use the transpose. + // For safe inverse transforms, xform by the affine_inverse. + _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; + _FORCE_INLINE_ Vector3i xform_inv(const Vector3i &p_vector) const; + _FORCE_INLINE_ AABB xform_inv(const AABB &p_aabb) const; + _FORCE_INLINE_ PoolVector xform_inv(const PoolVector &p_array) const; + _FORCE_INLINE_ PoolVector xform_inv(const PoolVector &p_array) const; + + // Safe with non-uniform scaling (uses affine_inverse). + _FORCE_INLINE_ Plane xform(const Plane &p_plane) const; + _FORCE_INLINE_ Plane xform_inv(const Plane &p_plane) const; + + // These fast versions use precomputed affine inverse, and should be used in bottleneck areas where + // multiple planes are to be transformed. + _FORCE_INLINE_ Plane xform_fast(const Plane &p_plane, const Basis &p_basis_inverse_transpose) const; + static _FORCE_INLINE_ Plane xform_inv_fast(const Plane &p_plane, const Transform &p_inverse, const Basis &p_basis_transpose); + + void operator*=(const Transform &p_transform); + Transform operator*(const Transform &p_transform) const; + void operator*=(const real_t p_val); + Transform operator*(const real_t p_val) const; + + Transform spherical_interpolate_with(const Transform &p_transform, real_t p_c) const; + Transform interpolate_with(const Transform &p_transform, real_t p_c) const; + + _FORCE_INLINE_ Transform inverse_xform(const Transform &t) const { + Vector3 v = t.origin - origin; + return Transform(basis.transpose_xform(t.basis), + basis.xform(v)); + } + + void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t tx, real_t ty, real_t tz) { + basis.set(xx, xy, xz, yx, yy, yz, zx, zy, zz); + origin.x = tx; + origin.y = ty; + origin.z = tz; + } + + operator String() const; + + Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); + Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3()); + Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); + Transform() {} +}; + +_FORCE_INLINE_ Vector3 Transform::xform(const Vector3 &p_vector) const { + return Vector3( + basis[0].dot(p_vector) + origin.x, + basis[1].dot(p_vector) + origin.y, + basis[2].dot(p_vector) + origin.z); +} + +_FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { + Vector3 v = p_vector - origin; + + return Vector3( + (basis.rows[0][0] * v.x) + (basis.rows[1][0] * v.y) + (basis.rows[2][0] * v.z), + (basis.rows[0][1] * v.x) + (basis.rows[1][1] * v.y) + (basis.rows[2][1] * v.z), + (basis.rows[0][2] * v.x) + (basis.rows[1][2] * v.y) + (basis.rows[2][2] * v.z)); +} + +_FORCE_INLINE_ Vector3i Transform::xform(const Vector3i &p_vector) const { + return Vector3i( + basis[0].dot(p_vector) + origin.x, + basis[1].dot(p_vector) + origin.y, + basis[2].dot(p_vector) + origin.z); +} + +_FORCE_INLINE_ Vector3i Transform::xform_inv(const Vector3i &p_vector) const { + Vector3i v = p_vector; + v.x -= origin.x; + v.y -= origin.y; + v.z -= origin.z; + + return Vector3i( + (basis.rows[0][0] * v.x) + (basis.rows[1][0] * v.y) + (basis.rows[2][0] * v.z), + (basis.rows[0][1] * v.x) + (basis.rows[1][1] * v.y) + (basis.rows[2][1] * v.z), + (basis.rows[0][2] * v.x) + (basis.rows[1][2] * v.y) + (basis.rows[2][2] * v.z)); +} + +// Neither the plane regular xform or xform_inv are particularly efficient, +// as they do a basis inverse. For xforming a large number +// of planes it is better to pre-calculate the inverse transpose basis once +// and reuse it for each plane, by using the 'fast' version of the functions. +_FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { + Basis b = basis.inverse(); + b.transpose(); + return xform_fast(p_plane, b); +} + +_FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { + Transform inv = affine_inverse(); + Basis basis_transpose = basis.transposed(); + return xform_inv_fast(p_plane, inv, basis_transpose); +} + +_FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { + /* http://dev.theomader.com/transform-bounding-boxes/ */ + Vector3 min = p_aabb.position; + Vector3 max = p_aabb.position + p_aabb.size; + Vector3 tmin, tmax; + for (int i = 0; i < 3; i++) { + tmin[i] = tmax[i] = origin[i]; + for (int j = 0; j < 3; j++) { + real_t e = basis[i][j] * min[j]; + real_t f = basis[i][j] * max[j]; + if (e < f) { + tmin[i] += e; + tmax[i] += f; + } else { + tmin[i] += f; + tmax[i] += e; + } + } + } + AABB r_aabb; + r_aabb.position = tmin; + r_aabb.size = tmax - tmin; + return r_aabb; +} + +_FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { + /* define vertices */ + Vector3 vertices[8] = { + Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z), + Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z), + Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z), + Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y, p_aabb.position.z), + Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z), + Vector3(p_aabb.position.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z), + Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z + p_aabb.size.z), + Vector3(p_aabb.position.x, p_aabb.position.y, p_aabb.position.z) + }; + + AABB ret; + + ret.position = xform_inv(vertices[0]); + + for (int i = 1; i < 8; i++) { + ret.expand_to(xform_inv(vertices[i])); + } + + return ret; +} + +PoolVector Transform::xform(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform(r[i]); + } + return array; +} + +PoolVector Transform::xform(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform(r[i]); + } + return array; +} + +PoolVector Transform::xform_inv(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform_inv(r[i]); + } + return array; +} + +PoolVector Transform::xform_inv(const PoolVector &p_array) const { + PoolVector array; + array.resize(p_array.size()); + + PoolVector::Read r = p_array.read(); + PoolVector::Write w = array.write(); + + for (int i = 0; i < p_array.size(); ++i) { + w[i] = xform_inv(r[i]); + } + return array; +} + +_FORCE_INLINE_ Plane Transform::xform_fast(const Plane &p_plane, const Basis &p_basis_inverse_transpose) const { + // Transform a single point on the plane. + Vector3 point = p_plane.normal * p_plane.d; + point = xform(point); + + // Use inverse transpose for correct normals with non-uniform scaling. + Vector3 normal = p_basis_inverse_transpose.xform(p_plane.normal); + normal.normalize(); + + real_t d = normal.dot(point); + return Plane(normal, d); +} + +_FORCE_INLINE_ Plane Transform::xform_inv_fast(const Plane &p_plane, const Transform &p_inverse, const Basis &p_basis_transpose) { + // Transform a single point on the plane. + Vector3 point = p_plane.normal * p_plane.d; + point = p_inverse.xform(point); + + // Note that instead of precalculating the transpose, an alternative + // would be to use the transpose for the basis transform. + // However that would be less SIMD friendly (requiring a swizzle). + // So the cost is one extra precalced value in the calling code. + // This is probably worth it, as this could be used in bottleneck areas. And + // where it is not a bottleneck, the non-fast method is fine. + + // Use transpose for correct normals with non-uniform scaling. + Vector3 normal = p_basis_transpose.xform(p_plane.normal); + normal.normalize(); + + real_t d = normal.dot(point); + return Plane(normal, d); +} + +#line 0 + +#line 1 "sfw/core/hashfuncs.h" /*************************************************************************/ /* hashfuncs.h */ @@ -10776,6 +14907,37 @@ struct HashMapHasherDefault { h = hash_murmur3_one_32(p_vec.y, h); return hash_fmix32(h); } + static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) { + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + h = hash_murmur3_one_32(p_vec.z, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) { + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + h = hash_murmur3_one_32(p_vec.z, h); + h = hash_murmur3_one_32(p_vec.w, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) { + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) { + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + h = hash_murmur3_one_real(p_vec.z, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) { + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + h = hash_murmur3_one_real(p_vec.z, h); + h = hash_murmur3_one_real(p_vec.w, h); + return hash_fmix32(h); + } static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) { uint32_t h = hash_murmur3_one_32(p_rect.position.x); h = hash_murmur3_one_32(p_rect.position.y, h); @@ -10783,6 +14945,22 @@ struct HashMapHasherDefault { h = hash_murmur3_one_32(p_rect.size.y, h); return hash_fmix32(h); } + static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) { + uint32_t h = hash_murmur3_one_real(p_rect.position.x); + h = hash_murmur3_one_real(p_rect.position.y, h); + h = hash_murmur3_one_real(p_rect.size.x, h); + h = hash_murmur3_one_real(p_rect.size.y, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) { + uint32_t h = hash_murmur3_one_real(p_aabb.position.x); + h = hash_murmur3_one_real(p_aabb.position.y, h); + h = hash_murmur3_one_real(p_aabb.position.z, h); + h = hash_murmur3_one_real(p_aabb.size.x, h); + h = hash_murmur3_one_real(p_aabb.size.y, h); + h = hash_murmur3_one_real(p_aabb.size.z, h); + return hash_fmix32(h); + } }; template @@ -10806,6 +14984,20 @@ struct HashMapComparatorDefault { } }; +template <> +struct HashMapComparatorDefault { + static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) { + return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) { + return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))); + } +}; + constexpr uint32_t HASH_TABLE_SIZE_MAX = 29; const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { @@ -10904,7 +15096,7 @@ static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const #line 0 -#line 1 "sfwl/core/pair.h" +#line 1 "sfw/core/pair.h" /*************************************************************************/ /* pair.h */ @@ -10991,7 +15183,7 @@ struct KeyValueSort { #line 0 -#line 1 "sfwl/core/og_hash_map.h" +#line 1 "sfw/core/og_hash_map.h" /*************************************************************************/ /* og_hash_map.h */ @@ -11563,7 +15755,7 @@ public: #line 0 -#line 1 "sfwl/core/ordered_hash_map.h" +#line 1 "sfw/core/ordered_hash_map.h" /*************************************************************************/ /* ordered_hash_map.h */ @@ -11844,7 +16036,7 @@ public: #line 0 -#line 1 "sfwl/core/hash_map.h" +#line 1 "sfw/core/hash_map.h" /*************************************************************************/ /* hash_map.h */ @@ -12478,7 +16670,7 @@ private: #line 0 -#line 1 "sfwl/core/hash_set.h" +#line 1 "sfw/core/hash_set.h" /*************************************************************************/ /* hash_set.h */ @@ -12953,7 +17145,7 @@ public: #line 0 -#line 1 "sfwl/core/file_access.h" +#line 1 "sfw/core/file_access.h" /*************************************************************************/ /* file_access.h */ @@ -13149,7 +17341,7 @@ struct FileAccessRef { #line 0 -#line 1 "sfwl/core/dir_access.h" +#line 1 "sfw/core/dir_access.h" /*************************************************************************/ /* dir_access.h */ @@ -13287,7 +17479,7 @@ struct DirAccessRef { #line 0 -#line 1 "sfwl/core/inet_address.h" +#line 1 "sfw/core/inet_address.h" //Based on: // Copyright 2010, Shuo Chen. All rights reserved. @@ -13369,7 +17561,7 @@ private: #line 0 -#line 1 "sfwl/core/socket.h" +#line 1 "sfw/core/socket.h" //Based on: @@ -13430,7 +17622,7 @@ public: #line 0 -#line 1 "sfwl/core/sub_process.h" +#line 1 "sfw/core/sub_process.h" /*************************************************************************/ /* sub_process.h */ @@ -13570,7 +17762,7 @@ struct SubProcessRef { #line 0 -#line 1 "sfwl/core/sfw_core.h" +#line 1 "sfw/core/sfw_core.h" class SFWCore { public: @@ -13585,7 +17777,7 @@ protected: //=================== OBJECT SECTION =================== -#line 1 "sfwl/object/ref_ptr.h" +#line 1 "sfw/object/ref_ptr.h" /*************************************************************************/ /* ref_ptr.h */ @@ -13619,7 +17811,7 @@ public: #line 0 -#line 1 "sfwl/object/object_id.h" +#line 1 "sfw/object/object_id.h" /*************************************************************************/ /* object_id.h */ @@ -13630,7 +17822,7 @@ typedef uint64_t ObjectID; #line 0 -#line 1 "sfwl/object/core_string_names.h" +#line 1 "sfw/object/core_string_names.h" /*************************************************************************/ /* core_string_names.h */ @@ -13694,7 +17886,7 @@ public: #line 0 -#line 1 "sfwl/object/array.h" +#line 1 "sfw/object/array.h" /*************************************************************************/ /* array.h */ @@ -13782,7 +17974,7 @@ public: #line 0 -#line 1 "sfwl/object/dictionary.h" +#line 1 "sfw/object/dictionary.h" /*************************************************************************/ /* dictionary.h */ @@ -13848,7 +18040,7 @@ public: #line 0 -#line 1 "sfwl/object/variant.h" +#line 1 "sfw/object/variant.h" /*************************************************************************/ /* variant.h */ @@ -13862,7 +18054,12 @@ typedef PoolVector PoolByteArray; typedef PoolVector PoolIntArray; typedef PoolVector PoolRealArray; typedef PoolVector PoolStringArray; +typedef PoolVector PoolVector2Array; typedef PoolVector PoolVector2iArray; +typedef PoolVector PoolVector3Array; +typedef PoolVector PoolVector3iArray; +typedef PoolVector PoolVector4Array; +typedef PoolVector PoolVector4iArray; typedef PoolVector PoolColorArray; // Temporary workaround until c++11 alignas() @@ -13893,8 +18090,22 @@ public: STRING, // math types + RECT2, RECT2I, + VECTOR2, VECTOR2I, + VECTOR3, + VECTOR3I, + VECTOR4, + VECTOR4I, + + PLANE, + QUATERNION, + AABB, + BASIS, + TRANSFORM, + TRANSFORM2D, + PROJECTION, // misc types COLOR, @@ -13908,10 +18119,15 @@ public: POOL_INT_ARRAY, POOL_REAL_ARRAY, POOL_STRING_ARRAY, + POOL_VECTOR2_ARRAY, POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, + POOL_VECTOR4_ARRAY, + POOL_VECTOR4I_ARRAY, POOL_COLOR_ARRAY, - VARIANT_MAX + VARIANT_MAX // 38 }; @@ -13942,6 +18158,11 @@ private: bool _bool; int64_t _int; double _real; + Transform2D *_transform2d; + ::AABB *_aabb; + Basis *_basis; + Transform *_transform; + Projection *_projection; void *_ptr; //generic pointer uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]; } _data GCC_ALIGNED_8; @@ -13986,8 +18207,21 @@ public: operator double() const; operator String() const; operator StringName() const; + operator Rect2() const; operator Rect2i() const; + operator Vector2() const; operator Vector2i() const; + operator Vector3() const; + operator Vector3i() const; + operator Vector4() const; + operator Vector4i() const; + operator Plane() const; + operator ::AABB() const; + operator Quaternion() const; + operator Basis() const; + operator Transform() const; + operator Transform2D() const; + operator Projection() const; operator Color() const; operator RefPtr() const; @@ -14001,8 +18235,15 @@ public: operator PoolVector() const; operator PoolVector() const; operator PoolVector() const; + operator PoolVector() const; operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; operator Vector() const; operator Vector() const; @@ -14010,9 +18251,16 @@ public: operator Vector() const; operator Vector() const; operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; operator Vector() const; + operator Vector() const; operator Vector() const; + operator Vector() const; + // some core type enums to convert to operator Margin() const; operator Side() const; @@ -14038,20 +18286,40 @@ public: Variant(const StringName &p_string); Variant(const char *const p_cstring); Variant(const CharType *p_wstring); + Variant(const Vector2 &p_vector2); Variant(const Vector2i &p_vector2); + Variant(const Rect2 &p_rect2); Variant(const Rect2i &p_rect2); + Variant(const Vector3 &p_vector3); + Variant(const Vector3i &p_vector3); + Variant(const Vector4 &p_vector4); + Variant(const Vector4i &p_vector4); + Variant(const Projection &p_projection); + Variant(const Plane &p_plane); + Variant(const ::AABB &p_aabb); + Variant(const Quaternion &p_quat); + Variant(const Basis &p_matrix); + Variant(const Transform2D &p_transform); + Variant(const Transform &p_transform); Variant(const Color &p_color); Variant(const RefPtr &p_resource); Variant(const Object *p_object); Variant(const Dictionary &p_dictionary); Variant(const Array &p_array); + Variant(const PoolVector &p_array); Variant(const PoolVector &p_raw_array); Variant(const PoolVector &p_int_array); Variant(const PoolVector &p_real_array); Variant(const PoolVector &p_string_array); + Variant(const PoolVector &p_vector3_array); + Variant(const PoolVector &p_vector3_array); Variant(const PoolVector &p_color_array); + Variant(const PoolVector &p_face_array); + Variant(const PoolVector &p_vector2_array); Variant(const PoolVector &p_vector2_array); + Variant(const PoolVector &p_vector4_array); + Variant(const PoolVector &p_vector4_array); Variant(const Vector &p_array); Variant(const Vector &p_array); @@ -14059,8 +18327,14 @@ public: Variant(const Vector &p_array); Variant(const Vector &p_array); Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); // If this changes the table in variant_op must be updated enum Operator { @@ -14185,7 +18459,7 @@ String vformat(const String &p_text, const Variant &p1 = Variant(), const Varian #line 0 -#line 1 "sfwl/object/psignal.h" +#line 1 "sfw/object/psignal.h" class Signal { public: @@ -14350,7 +18624,7 @@ bool Signal::is_connected(T *obj, void (*func)(T *, Signal *)) { #line 0 -#line 1 "sfwl/object/object.h" +#line 1 "sfw/object/object.h" /*************************************************************************/ /* object.h */ @@ -14621,7 +18895,7 @@ public: #line 0 -#line 1 "sfwl/object/object_rc.h" +#line 1 "sfw/object/object_rc.h" /*************************************************************************/ /* object_rc.h */ @@ -14668,7 +18942,7 @@ public: #line 0 -#line 1 "sfwl/object/reference.h" +#line 1 "sfw/object/reference.h" /*************************************************************************/ /* reference.h */ @@ -14931,7 +19205,7 @@ public: #line 0 -#line 1 "sfwl/object/resource.h" +#line 1 "sfw/object/resource.h" class Resource : public Reference { SFW_OBJECT(Resource, Reference); diff --git a/platform/sfw_compat.h b/platform/sfw_compat.h new file mode 100644 index 0000000..439a6fd --- /dev/null +++ b/platform/sfw_compat.h @@ -0,0 +1,5 @@ + +#ifndef SFW_COMPAT_H +#define SFW_COMPAT_H + +#endif diff --git a/platform/sfwl_compat.h b/platform/sfwl_compat.h deleted file mode 100644 index 25364ac..0000000 --- a/platform/sfwl_compat.h +++ /dev/null @@ -1,5 +0,0 @@ - -#ifndef SFWL_COMPAT_H -#define SFWL_COMPAT_H - -#endif