diff options
Diffstat (limited to 'core')
69 files changed, 808 insertions, 656 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 562cbbdd27..f37e7f5956 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -42,6 +42,8 @@ #include "core/os/os.h" #include "core/variant/variant_parser.h" +const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot"; + ProjectSettings *ProjectSettings::singleton = nullptr; ProjectSettings *ProjectSettings::get_singleton() { @@ -521,7 +523,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo } // Updating the default value after the project settings have loaded. - project_data_dir_name = GLOBAL_GET("application/config/project_data_dir_name"); + bool use_hidden_directory = GLOBAL_GET("application/config/use_hidden_project_data_directory"); + project_data_dir_name = (use_hidden_directory ? "." : "") + PROJECT_DATA_DIR_NAME_SUFFIX; // Using GLOBAL_GET on every block for compressing can be slow, so assigning here. Compression::zstd_long_distance_matching = GLOBAL_GET("compression/formats/zstd/long_distance_matching"); @@ -1094,7 +1097,7 @@ ProjectSettings::ProjectSettings() { custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"); GLOBAL_DEF("application/run/disable_stdout", false); GLOBAL_DEF("application/run/disable_stderr", false); - project_data_dir_name = GLOBAL_DEF_RST("application/config/project_data_dir_name", ".godot"); + GLOBAL_DEF_RST("application/config/use_hidden_project_data_directory", true); GLOBAL_DEF("application/config/use_custom_user_dir", false); GLOBAL_DEF("application/config/custom_user_dir_name", ""); GLOBAL_DEF("application/config/project_settings_override", ""); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index 82f04b94df..ca37401751 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -42,6 +42,7 @@ class ProjectSettings : public Object { public: typedef Map<String, Variant> CustomMap; + static const String PROJECT_DATA_DIR_NAME_SUFFIX; enum { //properties that are not for built in values begin from this value, so builtin ones are displayed first diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 3a4fddc670..b1858c6b32 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -235,6 +235,19 @@ int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r return exitcode; } +int OS::create_instance(const Vector<String> &p_arguments) { + List<String> args; + for (int i = 0; i < p_arguments.size(); i++) { + args.push_back(p_arguments[i]); + } + ::OS::ProcessID pid = 0; + Error err = ::OS::get_singleton()->create_instance(args, &pid); + if (err != OK) { + return -1; + } + return pid; +} + int OS::create_process(const String &p_path, const Vector<String> &p_arguments) { List<String> args; for (int i = 0; i < p_arguments.size(); i++) { @@ -537,6 +550,7 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path); ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr"), &OS::execute, DEFVAL(Array()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_process", "path", "arguments"), &OS::create_process); + ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance); ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill); ClassDB::bind_method(D_METHOD("shell_open", "uri"), &OS::shell_open); ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id); @@ -603,8 +617,8 @@ void OS::_bind_methods() { ADD_PROPERTY_DEFAULT("low_processor_usage_mode", false); ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900); - BIND_ENUM_CONSTANT(VIDEO_DRIVER_GLES2); BIND_ENUM_CONSTANT(VIDEO_DRIVER_VULKAN); + BIND_ENUM_CONSTANT(VIDEO_DRIVER_OPENGL_3); BIND_ENUM_CONSTANT(DAY_SUNDAY); BIND_ENUM_CONSTANT(DAY_MONDAY); diff --git a/core/core_bind.h b/core/core_bind.h index 4eab085dda..72865f583c 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -119,8 +119,8 @@ protected: public: enum VideoDriver { - VIDEO_DRIVER_GLES2, VIDEO_DRIVER_VULKAN, + VIDEO_DRIVER_OPENGL_3, }; enum Weekday { @@ -165,6 +165,7 @@ public: String get_executable_path() const; int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false); int create_process(const String &p_path, const Vector<String> &p_arguments); + int create_instance(const Vector<String> &p_arguments); Error kill(int p_pid); Error shell_open(String p_uri); @@ -205,7 +206,7 @@ public: void delay_usec(int p_usec) const; void delay_msec(int p_msec) const; - uint32_t get_ticks_msec() const; + uint64_t get_ticks_msec() const; uint64_t get_ticks_usec() const; bool can_use_threads() const; diff --git a/core/core_builders.py b/core/core_builders.py index 004475faa7..b07daa80ae 100644 --- a/core/core_builders.py +++ b/core/core_builders.py @@ -35,7 +35,9 @@ def make_certs_header(target, source, env): decomp_size = len(buf) import zlib - buf = zlib.compress(buf) + # Use maximum zlib compression level to further reduce file size + # (at the cost of initial build times). + buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) g.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n") g.write("#ifndef CERTS_COMPRESSED_GEN_H\n") diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 9967d1e361..4607bd2f3f 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -79,8 +79,8 @@ public: ERR_FAIL_COND_V(p_buffer.size() == 0, 0); int total_bandwidth = 0; - uint32_t timestamp = OS::get_singleton()->get_ticks_msec(); - uint32_t final_timestamp = timestamp - 1000; + uint64_t timestamp = OS::get_singleton()->get_ticks_msec(); + uint64_t final_timestamp = timestamp - 1000; int i = (p_pointer + p_buffer.size() - 1) % p_buffer.size(); diff --git a/core/doc_data.h b/core/doc_data.h index 19dec71927..c75cdfcde5 100644 --- a/core/doc_data.h +++ b/core/doc_data.h @@ -140,7 +140,9 @@ public: String brief_description; String description; Vector<TutorialDoc> tutorials; + Vector<MethodDoc> constructors; Vector<MethodDoc> methods; + Vector<MethodDoc> operators; Vector<MethodDoc> signals; Vector<ConstantDoc> constants; Map<String, String> enums; diff --git a/core/input/input.cpp b/core/input/input.cpp index 296aa1f071..12028efc56 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -133,6 +133,7 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_mouse_cursor", "image", "shape", "hotspot"), &Input::set_custom_mouse_cursor, DEFVAL(CURSOR_ARROW), DEFVAL(Vector2())); ClassDB::bind_method(D_METHOD("parse_input_event", "event"), &Input::parse_input_event); ClassDB::bind_method(D_METHOD("set_use_accumulated_input", "enable"), &Input::set_use_accumulated_input); + ClassDB::bind_method(D_METHOD("flush_buffered_events"), &Input::flush_buffered_events); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); @@ -163,10 +164,11 @@ void Input::_bind_methods() { void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { String pf = p_function; - if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || - pf == "is_action_just_pressed" || pf == "is_action_just_released" || - pf == "get_action_strength" || pf == "get_action_raw_strength" || - pf == "get_axis" || pf == "get_vector")) { + if (p_idx == 0 && + (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" || + pf == "is_action_just_pressed" || pf == "is_action_just_released" || + pf == "get_action_strength" || pf == "get_action_raw_strength" || + pf == "get_axis" || pf == "get_vector")) { List<PropertyInfo> pinfo; ProjectSettings::get_singleton()->get_property_list(&pinfo); @@ -314,11 +316,11 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po if (p_deadzone < 0.0f) { // If the deadzone isn't specified, get it from the average of the actions. - p_deadzone = (InputMap::get_singleton()->action_get_deadzone(p_positive_x) + - InputMap::get_singleton()->action_get_deadzone(p_negative_x) + - InputMap::get_singleton()->action_get_deadzone(p_positive_y) + - InputMap::get_singleton()->action_get_deadzone(p_negative_y)) / - 4; + p_deadzone = 0.25 * + (InputMap::get_singleton()->action_get_deadzone(p_positive_x) + + InputMap::get_singleton()->action_get_deadzone(p_negative_x) + + InputMap::get_singleton()->action_get_deadzone(p_positive_y) + + InputMap::get_singleton()->action_get_deadzone(p_negative_y)); } // Circular length limiting and deadzone. diff --git a/core/input/input.h b/core/input/input.h index 6819fc8eb0..f63138a875 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -265,7 +265,6 @@ public: float get_joy_vibration_duration(int p_device); uint64_t get_joy_vibration_timestamp(int p_device); void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = ""); - void parse_joypad_mapping(String p_mapping, bool p_update_existing); Vector3 get_gravity() const; Vector3 get_accelerometer() const; diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index c6448b1e44..af3190bb17 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -454,10 +454,10 @@ bool InputEventKey::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) if (keycode == 0) { return physical_keycode == key->physical_keycode && - (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); + (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); } else { return keycode == key->keycode && - (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); + (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); } } @@ -616,7 +616,7 @@ bool InputEventMouseButton::is_match(const Ref<InputEvent> &p_event, bool p_exac } return button_index == mb->button_index && - (!p_exact_match || get_modifiers_mask() == mb->get_modifiers_mask()); + (!p_exact_match || get_modifiers_mask() == mb->get_modifiers_mask()); } static const char *_mouse_button_descriptions[9] = { @@ -935,7 +935,7 @@ bool InputEventJoypadMotion::is_match(const Ref<InputEvent> &p_event, bool p_exa } return axis == jm->axis && - (!p_exact_match || ((axis_value < 0) == (jm->axis_value < 0))); + (!p_exact_match || ((axis_value < 0) == (jm->axis_value < 0))); } static const char *_joy_axis_descriptions[JOY_AXIS_MAX] = { diff --git a/core/input/input_map.h b/core/input/input_map.h index 8bef722089..0bf572ddca 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -41,8 +41,8 @@ class InputMap : public Object { public: /** - * A special value used to signify that a given Action can be triggered by any device - */ + * A special value used to signify that a given Action can be triggered by any device + */ static int ALL_DEVICES; struct Action { diff --git a/core/io/compression.h b/core/io/compression.h index cbfed74124..06f26876e5 100644 --- a/core/io/compression.h +++ b/core/io/compression.h @@ -54,8 +54,6 @@ public: static int get_max_compressed_buffer_size(int p_src_size, Mode p_mode = MODE_ZSTD); static int decompress(uint8_t *p_dst, int p_dst_max_size, const uint8_t *p_src, int p_src_size, Mode p_mode = MODE_ZSTD); static int decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_size, const uint8_t *p_src, int p_src_size, Mode p_mode); - - Compression() {} }; #endif // COMPRESSION_H diff --git a/core/io/image.cpp b/core/io/image.cpp index c70f4b86bd..b82e6637b4 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -797,7 +797,7 @@ static void _scale_bilinear(const uint8_t *__restrict p_src, uint8_t *__restrict uint32_t interp_down = p01 + (((p11 - p01) * src_xofs_frac) >> FRAC_BITS); uint32_t interp = interp_up + (((interp_down - interp_up) * src_yofs_frac) >> FRAC_BITS); interp >>= FRAC_BITS; - p_dst[i * p_dst_width * CC + j * CC + l] = interp; + p_dst[i * p_dst_width * CC + j * CC + l] = uint8_t(interp); } else if (sizeof(T) == 2) { //half float float xofs_frac = float(src_xofs_frac) / (1 << FRAC_BITS); diff --git a/core/io/image.h b/core/io/image.h index 8f1b251ac3..d31a065aa7 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -41,7 +41,7 @@ * Image storage class. This is used to store an image in user memory, as well as * providing some basic methods for image manipulation. * Images can be loaded from a file, or registered into the Render object as textures. -*/ + */ class Image; diff --git a/core/io/logger.h b/core/io/logger.h index f244f70e7e..48b073aa45 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -83,7 +83,6 @@ class RotatedFileLogger : public Logger { FileAccess *file = nullptr; - void rotate_file_without_closing(); void close_file(); void clear_old_backups(); void rotate_file(); diff --git a/core/io/marshalls.h b/core/io/marshalls.h index 05804d5a46..9ea060e48c 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -44,9 +44,9 @@ typedef uint32_t uintr_t; #endif /** - * Miscellaneous helpers for marshalling data types, and encoding - * in an endian independent way - */ + * Miscellaneous helpers for marshalling data types, and encoding + * in an endian independent way + */ union MarshallFloat { uint32_t i; ///< int diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index d59dbf1ba8..1079da75ef 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -239,7 +239,7 @@ bool AStar::are_points_connected(int p_id, int p_with_id, bool bidirectional) co const Set<Segment>::Element *element = segments.find(s); return element != nullptr && - (bidirectional || (element->get().direction & s.direction) == s.direction); + (bidirectional || (element->get().direction & s.direction) == s.direction); } void AStar::clear() { diff --git a/core/math/aabb.h b/core/math/aabb.h index 97d92fbe37..c458e61475 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -200,7 +200,7 @@ Vector3 AABB::get_support(const Vector3 &p_normal) const { (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; + ofs; } Vector3 AABB::get_endpoint(int p_point) const { diff --git a/core/math/basis.cpp b/core/math/basis.cpp index a7f89522d7..3d893afb4d 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -58,8 +58,8 @@ void Basis::invert() { cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1) }; real_t det = elements[0][0] * co[0] + - elements[0][1] * co[1] + - elements[0][2] * co[2]; + elements[0][1] * co[1] + + elements[0][2] * co[2]; #ifdef MATH_CHECKS ERR_FAIL_COND(det == 0); #endif @@ -288,10 +288,7 @@ Vector3 Basis::get_scale() const { // // The rotation part of this decomposition is returned by get_rotation* functions. real_t det_sign = SGN(determinant()); - return det_sign * Vector3( - Vector3(elements[0][0], elements[1][0], elements[2][0]).length(), - Vector3(elements[0][1], elements[1][1], elements[2][1]).length(), - Vector3(elements[0][2], elements[1][2], elements[2][2]).length()); + 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. @@ -354,7 +351,7 @@ void Basis::rotate(const Quaternion &p_quaternion) { *this = rotated(p_quaternion); } -Vector3 Basis::get_rotation_euler() const { +Vector3 Basis::get_euler_normalized(EulerOrder p_order) 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. @@ -365,7 +362,7 @@ Vector3 Basis::get_rotation_euler() const { m.scale(Vector3(-1, -1, -1)); } - return m.get_euler(); + return m.get_euler(p_order); } Quaternion Basis::get_rotation_quaternion() const { @@ -424,218 +421,203 @@ void Basis::get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) cons 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 = elements[0][2]; - if (sy < (1.0 - CMP_EPSILON)) { - if (sy > -(1.0 - CMP_EPSILON)) { - // is this a pure Y rotation? - if (elements[1][0] == 0.0 && elements[0][1] == 0.0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) { - // return the simplest form (human friendlier in editor and scripts) - euler.x = 0; - euler.y = atan2(elements[0][2], elements[0][0]); - euler.z = 0; +Vector3 Basis::get_euler(EulerOrder p_order) const { + switch (p_order) { + case EULER_ORDER_XYZ: { + // 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 = elements[0][2]; + if (sy < (1.0 - CMP_EPSILON)) { + if (sy > -(1.0 - CMP_EPSILON)) { + // is this a pure Y rotation? + if (elements[1][0] == 0.0 && elements[0][1] == 0.0 && elements[1][2] == 0 && elements[2][1] == 0 && elements[1][1] == 1) { + // return the simplest form (human friendlier in editor and scripts) + euler.x = 0; + euler.y = atan2(elements[0][2], elements[0][0]); + euler.z = 0; + } else { + euler.x = Math::atan2(-elements[1][2], elements[2][2]); + euler.y = Math::asin(sy); + euler.z = Math::atan2(-elements[0][1], elements[0][0]); + } + } else { + euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.y = -Math_PI / 2.0; + euler.z = 0.0; + } } else { - euler.x = Math::atan2(-elements[1][2], elements[2][2]); - euler.y = Math::asin(sy); - euler.z = Math::atan2(-elements[0][1], elements[0][0]); + euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.y = Math_PI / 2.0; + euler.z = 0.0; + } + return euler; + } break; + case EULER_ORDER_XZY: { + // 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 = elements[0][1]; + if (sz < (1.0 - CMP_EPSILON)) { + if (sz > -(1.0 - CMP_EPSILON)) { + euler.x = Math::atan2(elements[2][1], elements[1][1]); + euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.z = Math::asin(-sz); + } else { + // It's -1 + euler.x = -Math::atan2(elements[1][2], elements[2][2]); + euler.y = 0.0; + euler.z = Math_PI / 2.0; + } + } else { + // It's 1 + euler.x = -Math::atan2(elements[1][2], elements[2][2]); + euler.y = 0.0; + euler.z = -Math_PI / 2.0; + } + return euler; + } break; + case EULER_ORDER_YXZ: { + // 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 = elements[1][2]; + + if (m12 < (1 - CMP_EPSILON)) { + if (m12 > -(1 - CMP_EPSILON)) { + // is this a pure X rotation? + if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) { + // return the simplest form (human friendlier in editor and scripts) + euler.x = atan2(-m12, elements[1][1]); + euler.y = 0; + euler.z = 0; + } else { + euler.x = asin(-m12); + euler.y = atan2(elements[0][2], elements[2][2]); + euler.z = atan2(elements[1][0], elements[1][1]); + } + } else { // m12 == -1 + euler.x = Math_PI * 0.5; + euler.y = atan2(elements[0][1], elements[0][0]); + euler.z = 0; + } + } else { // m12 == 1 + euler.x = -Math_PI * 0.5; + euler.y = -atan2(elements[0][1], elements[0][0]); + euler.z = 0; } - } else { - euler.x = Math::atan2(elements[2][1], elements[1][1]); - euler.y = -Math_PI / 2.0; - euler.z = 0.0; - } - } else { - euler.x = Math::atan2(elements[2][1], elements[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, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - //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 = elements[0][1]; - if (sz < (1.0 - CMP_EPSILON)) { - if (sz > -(1.0 - CMP_EPSILON)) { - euler.x = Math::atan2(elements[2][1], elements[1][1]); - euler.y = Math::atan2(elements[0][2], elements[0][0]); - euler.z = Math::asin(-sz); - } else { - // It's -1 - euler.x = -Math::atan2(elements[1][2], elements[2][2]); - euler.y = 0.0; - euler.z = Math_PI / 2.0; - } - } else { - // It's 1 - euler.x = -Math::atan2(elements[1][2], elements[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, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *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 = elements[1][0]; - if (sz < (1.0 - CMP_EPSILON)) { - if (sz > -(1.0 - CMP_EPSILON)) { - euler.x = Math::atan2(-elements[1][2], elements[1][1]); - euler.y = Math::atan2(-elements[2][0], elements[0][0]); - euler.z = Math::asin(sz); - } else { - // It's -1 - euler.x = Math::atan2(elements[2][1], elements[2][2]); - euler.y = 0.0; - euler.z = -Math_PI / 2.0; - } - } else { - // It's 1 - euler.x = Math::atan2(elements[2][1], elements[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, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *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 = elements[1][2]; - if (m12 < (1 - CMP_EPSILON)) { - if (m12 > -(1 - CMP_EPSILON)) { - // is this a pure X rotation? - if (elements[1][0] == 0 && elements[0][1] == 0 && elements[0][2] == 0 && elements[2][0] == 0 && elements[0][0] == 1) { - // return the simplest form (human friendlier in editor and scripts) - euler.x = atan2(-m12, elements[1][1]); - euler.y = 0; + return euler; + } break; + case EULER_ORDER_YZX: { + // 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 = elements[1][0]; + if (sz < (1.0 - CMP_EPSILON)) { + if (sz > -(1.0 - CMP_EPSILON)) { + euler.x = Math::atan2(-elements[1][2], elements[1][1]); + euler.y = Math::atan2(-elements[2][0], elements[0][0]); + euler.z = Math::asin(sz); + } else { + // It's -1 + euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.y = 0.0; + euler.z = -Math_PI / 2.0; + } + } else { + // It's 1 + euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.y = 0.0; + euler.z = Math_PI / 2.0; + } + return euler; + } break; + case EULER_ORDER_ZXY: { + // 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 = elements[2][1]; + if (sx < (1.0 - CMP_EPSILON)) { + if (sx > -(1.0 - CMP_EPSILON)) { + euler.x = Math::asin(sx); + euler.y = Math::atan2(-elements[2][0], elements[2][2]); + euler.z = Math::atan2(-elements[0][1], elements[1][1]); + } else { + // It's -1 + euler.x = -Math_PI / 2.0; + euler.y = Math::atan2(elements[0][2], elements[0][0]); + euler.z = 0; + } + } else { + // It's 1 + euler.x = Math_PI / 2.0; + euler.y = Math::atan2(elements[0][2], elements[0][0]); euler.z = 0; + } + return euler; + } break; + case EULER_ORDER_ZYX: { + // 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 = elements[2][0]; + if (sy < (1.0 - CMP_EPSILON)) { + if (sy > -(1.0 - CMP_EPSILON)) { + euler.x = Math::atan2(elements[2][1], elements[2][2]); + euler.y = Math::asin(-sy); + euler.z = Math::atan2(elements[1][0], elements[0][0]); + } else { + // It's -1 + euler.x = 0; + euler.y = Math_PI / 2.0; + euler.z = -Math::atan2(elements[0][1], elements[1][1]); + } } else { - euler.x = asin(-m12); - euler.y = atan2(elements[0][2], elements[2][2]); - euler.z = atan2(elements[1][0], elements[1][1]); + // It's 1 + euler.x = 0; + euler.y = -Math_PI / 2.0; + euler.z = -Math::atan2(elements[0][1], elements[1][1]); } - } else { // m12 == -1 - euler.x = Math_PI * 0.5; - euler.y = atan2(elements[0][1], elements[0][0]); - euler.z = 0; + return euler; + } break; + default: { + ERR_FAIL_V_MSG(Vector3(), "Invalid parameter for get_euler(order)"); } - } else { // m12 == 1 - euler.x = -Math_PI * 0.5; - euler.y = -atan2(elements[0][1], elements[0][0]); - euler.z = 0; } - - return euler; + return Vector3(); } -// 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) { +void Basis::set_euler(const Vector3 &p_euler, EulerOrder p_order) { real_t c, s; c = Math::cos(p_euler.x); @@ -650,102 +632,29 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) { s = Math::sin(p_euler.z); Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - //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 = elements[2][1]; - if (sx < (1.0 - CMP_EPSILON)) { - if (sx > -(1.0 - CMP_EPSILON)) { - euler.x = Math::asin(sx); - euler.y = Math::atan2(-elements[2][0], elements[2][2]); - euler.z = Math::atan2(-elements[0][1], elements[1][1]); - } else { - // It's -1 - euler.x = -Math_PI / 2.0; - euler.y = Math::atan2(elements[0][2], elements[0][0]); - euler.z = 0; + switch (p_order) { + case EULER_ORDER_XYZ: { + *this = xmat * (ymat * zmat); + } break; + case EULER_ORDER_XZY: { + *this = xmat * zmat * ymat; + } break; + case EULER_ORDER_YXZ: { + *this = ymat * xmat * zmat; + } break; + case EULER_ORDER_YZX: { + *this = ymat * zmat * xmat; + } break; + case EULER_ORDER_ZXY: { + *this = zmat * xmat * ymat; + } break; + case EULER_ORDER_ZYX: { + *this = zmat * ymat * xmat; + } break; + default: { + ERR_FAIL_MSG("Invalid order parameter for set_euler(vec3,order)"); } - } else { - // It's 1 - euler.x = Math_PI / 2.0; - euler.y = Math::atan2(elements[0][2], elements[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, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *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 = elements[2][0]; - if (sy < (1.0 - CMP_EPSILON)) { - if (sy > -(1.0 - CMP_EPSILON)) { - euler.x = Math::atan2(elements[2][1], elements[2][2]); - euler.y = Math::asin(-sy); - euler.z = Math::atan2(elements[1][0], elements[0][0]); - } else { - // It's -1 - euler.x = 0; - euler.y = Math_PI / 2.0; - euler.z = -Math::atan2(elements[0][1], elements[1][1]); - } - } else { - // It's 1 - euler.x = 0; - euler.y = -Math_PI / 2.0; - euler.z = -Math::atan2(elements[0][1], elements[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, 0.0, 0.0, c, -s, 0.0, s, c); - - c = Math::cos(p_euler.y); - s = Math::sin(p_euler.y); - Basis ymat(c, 0.0, s, 0.0, 1.0, 0.0, -s, 0.0, c); - - c = Math::cos(p_euler.z); - s = Math::sin(p_euler.z); - Basis zmat(c, -s, 0.0, s, c, 0.0, 0.0, 0.0, 1.0); - - *this = zmat * ymat * xmat; } bool Basis::is_equal_approx(const Basis &p_basis) const { @@ -770,8 +679,8 @@ bool Basis::operator!=(const Basis &p_matrix) const { Basis::operator String() const { return "[X: " + get_axis(0).operator String() + - ", Y: " + get_axis(1).operator String() + - ", Z: " + get_axis(2).operator String() + "]"; + ", Y: " + get_axis(1).operator String() + + ", Z: " + get_axis(2).operator String() + "]"; } Quaternion Basis::get_quaternion() const { @@ -792,9 +701,9 @@ Quaternion Basis::get_quaternion() const { temp[1] = ((m.elements[0][2] - m.elements[2][0]) * s); temp[2] = ((m.elements[1][0] - m.elements[0][1]) * s); } else { - int i = m.elements[0][0] < m.elements[1][1] ? - (m.elements[1][1] < m.elements[2][2] ? 2 : 1) : - (m.elements[0][0] < m.elements[2][2] ? 2 : 0); + int i = m.elements[0][0] < m.elements[1][1] + ? (m.elements[1][1] < m.elements[2][2] ? 2 : 1) + : (m.elements[0][0] < m.elements[2][2] ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; diff --git a/core/math/basis.h b/core/math/basis.h index eb107d7e4e..e2fdb95685 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -85,40 +85,35 @@ public: void rotate(const Quaternion &p_quaternion); Basis rotated(const Quaternion &p_quaternion) const; - Vector3 get_rotation_euler() const; + enum EulerOrder { + EULER_ORDER_XYZ, + EULER_ORDER_XZY, + EULER_ORDER_YXZ, + EULER_ORDER_YZX, + EULER_ORDER_ZXY, + EULER_ORDER_ZYX + }; + + Vector3 get_euler_normalized(EulerOrder p_order = EULER_ORDER_YXZ) 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(Vector3 p_start_direction, 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(EulerOrder p_order = EULER_ORDER_YXZ) const; + void set_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ); + static Basis from_euler(const Vector3 &p_euler, EulerOrder p_order = EULER_ORDER_YXZ) { + Basis b; + b.set_euler(p_euler, p_order); + return b; + } Quaternion get_quaternion() const; void set_quaternion(const Quaternion &p_quaternion); - Vector3 get_euler() const { return get_euler_yxz(); } - void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); } - void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const; void set_axis_angle(const Vector3 &p_axis, real_t p_phi); @@ -250,9 +245,6 @@ public: Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }; Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, 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); } static Basis from_scale(const Vector3 &p_scale); @@ -332,7 +324,7 @@ Vector3 Basis::xform_inv(const Vector3 &p_vector) const { real_t Basis::determinant() const { return elements[0][0] * (elements[1][1] * elements[2][2] - elements[2][1] * elements[1][2]) - - elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) + - elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]); + elements[1][0] * (elements[0][1] * elements[2][2] - elements[2][1] * elements[0][2]) + + elements[2][0] * (elements[0][1] * elements[1][2] - elements[1][1] * elements[0][2]); } #endif // BASIS_H diff --git a/core/math/bvh_logic.inc b/core/math/bvh_logic.inc index afab08f151..c65002a9fd 100644 --- a/core/math/bvh_logic.inc +++ b/core/math/bvh_logic.inc @@ -42,24 +42,24 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) { //-------------------------------------------------------------------------------------------------- /** -@file q3DynamicAABBTree.h -@author Randy Gaul -@date 10/10/2014 - Copyright (c) 2014 Randy Gaul http://www.randygaul.net - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not - be misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ + * @file q3DynamicAABBTree.h + * @author Randy Gaul + * @date 10/10/2014 + * Copyright (c) 2014 Randy Gaul http://www.randygaul.net + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ //-------------------------------------------------------------------------------------------------- // This function is based on the 'Balance' function from Randy Gaul's qu3e @@ -67,7 +67,7 @@ BVHABB_CLASS _logic_abb_merge(const BVHABB_CLASS &a, const BVHABB_CLASS &b) { // It is MODIFIED from qu3e version. // This is the only function used (and _logic_abb_merge helper function). int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) { - // return iA; // uncomment this to bypass balance + //return iA; // uncomment this to bypass balance TNode *A = &_nodes[iA]; @@ -75,12 +75,12 @@ int32_t _logic_balance(int32_t iA, uint32_t p_tree_id) { return iA; } - /* A - / \ - B C - / \ / \ - D E F G - */ + /* A + * / \ + * B C + * / \ / \ + * D E F G + */ CRASH_COND(A->num_children != 2); int32_t iB = A->children[0]; diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 8066a59281..48984c4d5b 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -35,17 +35,17 @@ float CameraMatrix::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]; + 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 CameraMatrix::set_identity() { diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp index f67035c803..f6560f1bea 100644 --- a/core/math/convex_hull.cpp +++ b/core/math/convex_hull.cpp @@ -265,8 +265,7 @@ public: } int32_t get_sign() const { - return ((int64_t)high < 0) ? -1 : (high || low) ? 1 : - 0; + return ((int64_t)high < 0) ? -1 : ((high || low) ? 1 : 0); } bool operator<(const Int128 &b) const { @@ -594,8 +593,6 @@ private: IntermediateHull() { } - - void print(); }; enum Orientation { NONE, @@ -737,8 +734,6 @@ int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const { return 0; } - // return (numerator * b.denominator > b.numerator * denominator) ? sign : (numerator * b.denominator < b.numerator * denominator) ? -sign : 0; - #ifdef USE_X86_64_ASM int32_t result; @@ -759,10 +754,9 @@ int32_t ConvexHullInternal::Rational64::compare(const Rational64 &b) const { : "=&b"(result), [tmp] "=&r"(tmp), "=a"(dummy) : "a"(denominator), [bn] "g"(b.numerator), [tn] "g"(numerator), [bd] "g"(b.denominator) : "%rdx", "cc"); - return result ? result ^ sign // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero) - // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero) - : - 0; + // if sign is +1, only bit 0 of result is inverted, which does not change the sign of result (and cannot result in zero) + // if sign is -1, all bits of result are inverted, which changes the sign of result (and again cannot result in zero) + return result ? result ^ sign : 0; #else @@ -795,8 +789,7 @@ int32_t ConvexHullInternal::Rational128::compare(const Rational128 &b) const { int32_t ConvexHullInternal::Rational128::compare(int64_t b) const { if (is_int_64) { int64_t a = sign * (int64_t)numerator.low; - return (a > b) ? 1 : (a < b) ? -1 : - 0; + return (a > b) ? 1 : ((a < b) ? -1 : 0); } if (b > 0) { if (sign <= 0) { @@ -1448,8 +1441,7 @@ void ConvexHullInternal::merge(IntermediateHull &p_h0, IntermediateHull &p_h1) { c1->edges = e; return; } else { - int32_t cmp = !min0 ? 1 : !min1 ? -1 : - min_cot0.compare(min_cot1); + int32_t cmp = !min0 ? 1 : (!min1 ? -1 : min_cot0.compare(min_cot1)); #ifdef DEBUG_CONVEX_HULL printf(" -> Result %d\n", cmp); #endif diff --git a/core/math/face3.h b/core/math/face3.h index 9e9026e54e..0a8c1c6041 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -48,13 +48,13 @@ public: 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 - */ + * + * @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; diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index 8e5830f9b3..6010159597 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -37,8 +37,6 @@ #include "core/templates/vector.h" class Geometry2D { - Geometry2D(); - public: static real_t get_closest_points_between_segments(const Vector2 &p1, const Vector2 &q1, const Vector2 &p2, const Vector2 &q2, Vector2 &c1, Vector2 &c2) { Vector2 d1 = q1 - p1; // Direction vector of segment S1. diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h index 766689e222..6a59b34585 100644 --- a/core/math/geometry_3d.h +++ b/core/math/geometry_3d.h @@ -36,8 +36,6 @@ #include "core/templates/vector.h" class Geometry3D { - Geometry3D(); - public: static void get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2, Vector3 &c1, Vector3 &c2) { // Do the function 'd' as defined by pb. I think it's a dot product of some sort. diff --git a/core/math/math_defs.h b/core/math/math_defs.h index c3a8f910c0..900e90a598 100644 --- a/core/math/math_defs.h +++ b/core/math/math_defs.h @@ -116,10 +116,10 @@ enum Corner { }; /** - * The "Real" type is an abstract type used for real numbers, such as 1.5, - * in contrast to integer numbers. Precision can be controlled with the - * presence or absence of the REAL_T_IS_DOUBLE define. - */ + * The "Real" type is an abstract type used for real numbers, such as 1.5, + * in contrast to integer numbers. Precision can be controlled with the + * presence or absence of the REAL_T_IS_DOUBLE define. + */ #ifdef REAL_T_IS_DOUBLE typedef double real_t; #else diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h index 4e4f566517..baff10af98 100644 --- a/core/math/math_funcs.h +++ b/core/math/math_funcs.h @@ -159,7 +159,7 @@ public: } ieee754; ieee754.f = p_val; return ((unsigned)(ieee754.u >> 32) & 0x7fffffff) == 0x7ff00000 && - ((unsigned)ieee754.u == 0); + ((unsigned)ieee754.u == 0); #else return isinf(p_val); #endif @@ -461,7 +461,7 @@ public: mantissa = 0; } hf = (((uint16_t)sign) << 15) | (uint16_t)((0x1F << 10)) | - (uint16_t)(mantissa >> 13); + (uint16_t)(mantissa >> 13); } // check if exponent is <= -15 else if (exp <= 0x38000000) { @@ -474,8 +474,8 @@ public: hf = 0; //denormals do not work for 3D, convert to zero } else { hf = (((uint16_t)sign) << 15) | - (uint16_t)((exp - 0x38000000) >> 13) | - (uint16_t)(mantissa >> 13); + (uint16_t)((exp - 0x38000000) >> 13) | + (uint16_t)(mantissa >> 13); } return hf; diff --git a/core/math/plane.cpp b/core/math/plane.cpp index 3c78b55b90..59f7918258 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -88,7 +88,7 @@ bool Plane::intersect_3(const Plane &p_plane1, const Plane &p_plane2, Vector3 *r *r_result = ((vec3_cross(normal1, normal2) * p_plane0.d) + (vec3_cross(normal2, normal0) * p_plane1.d) + (vec3_cross(normal0, normal1) * p_plane2.d)) / - denom; + denom; } return true; diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp index 3f1d2c58e5..944474686a 100644 --- a/core/math/quaternion.cpp +++ b/core/math/quaternion.cpp @@ -44,7 +44,7 @@ real_t Quaternion::angle_to(const Quaternion &p_to) const { // This implementation uses XYZ convention (Z is the first rotation). Vector3 Quaternion::get_euler_xyz() const { Basis m(*this); - return m.get_euler_xyz(); + return m.get_euler(Basis::EULER_ORDER_XYZ); } // get_euler_yxz returns a vector containing the Euler angles in the format @@ -56,7 +56,7 @@ Vector3 Quaternion::get_euler_yxz() const { 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(); + return m.get_euler(Basis::EULER_ORDER_YXZ); } void Quaternion::operator*=(const Quaternion &p_q) { @@ -189,6 +189,15 @@ Quaternion::operator String() const { return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } +Vector3 Quaternion::get_axis() const { + 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::Quaternion(const Vector3 &p_axis, real_t p_angle) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); diff --git a/core/math/quaternion.h b/core/math/quaternion.h index 35324323b3..e20ea74eb4 100644 --- a/core/math/quaternion.h +++ b/core/math/quaternion.h @@ -72,6 +72,9 @@ public: 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; + Vector3 get_axis() const; + float get_angle() const; + _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); diff --git a/core/math/rect2.h b/core/math/rect2.h index 2557959fa2..26e202589d 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -118,8 +118,8 @@ struct Rect2 { 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)); + ((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 { @@ -257,7 +257,7 @@ struct Rect2 { return Vector2( (p_normal.x > 0) ? -half_extents.x : half_extents.x, (p_normal.y > 0) ? -half_extents.y : half_extents.y) + - ofs; + ofs; } _FORCE_INLINE_ bool intersects_filled_polygon(const Vector2 *p_points, int p_point_count) const { @@ -367,8 +367,8 @@ struct Rect2i { 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)); + ((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 { diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 496a557844..df43c605f9 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -298,6 +298,6 @@ Transform2D Transform2D::operator*(const real_t p_val) const { Transform2D::operator String() const { return "[X: " + elements[0].operator String() + - ", Y: " + elements[1].operator String() + - ", O: " + elements[2].operator String() + "]"; + ", Y: " + elements[1].operator String() + + ", O: " + elements[2].operator String() + "]"; } diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 6ed3af2ba7..8a0e876d96 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -164,7 +164,7 @@ Vector2 Transform2D::xform(const Vector2 &p_vec) const { return Vector2( tdotx(p_vec), tdoty(p_vec)) + - elements[2]; + elements[2]; } Vector2 Transform2D::xform_inv(const Vector2 &p_vec) const { diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp index 4f4943c8ef..78ef117443 100644 --- a/core/math/transform_3d.cpp +++ b/core/math/transform_3d.cpp @@ -175,9 +175,9 @@ Transform3D Transform3D::operator*(const real_t p_val) const { Transform3D::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() + "]"; + ", Y: " + basis.get_axis(1).operator String() + + ", Z: " + basis.get_axis(2).operator String() + + ", O: " + origin.operator String() + "]"; } Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp index fa1588dbc5..28f1d96b14 100644 --- a/core/math/triangulate.cpp +++ b/core/math/triangulate.cpp @@ -42,18 +42,13 @@ real_t Triangulate::get_area(const Vector<Vector2> &contour) { return A * 0.5; } -/* - is_inside_triangle decides if a point P is Inside of the triangle - defined by A, B, C. - */ - +/* `is_inside_triangle` decides if a point P is inside the triangle + * defined by A, B, C. */ bool Triangulate::is_inside_triangle(real_t Ax, real_t Ay, real_t Bx, real_t By, real_t Cx, real_t Cy, real_t Px, real_t Py, - bool include_edges) - -{ + bool include_edges) { real_t ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; real_t cCROSSap, bCROSScp, aCROSSbp; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index 16e43d7d06..6259bdead0 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -160,10 +160,11 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c real_t t3 = t2 * t; Vector2 out; - out = 0.5 * ((p1 * 2.0) + - (-p0 + p2) * t + - (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + - (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); + out = 0.5 * + ((p1 * 2.0) + + (-p0 + p2) * t + + (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); return out; } diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index fa212c178a..42e3da0b27 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -93,10 +93,11 @@ Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, c real_t t3 = t2 * t; Vector3 out; - out = 0.5 * ((p1 * 2.0) + - (-p0 + p2) * t + - (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + - (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); + out = 0.5 * + ((p1 * 2.0) + + (-p0 + p2) * t + + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 + + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3); return out; } diff --git a/core/math/vector3.h b/core/math/vector3.h index e65ac31c02..dc9aa60458 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -32,9 +32,9 @@ #define VECTOR3_H #include "core/math/math_funcs.h" +#include "core/math/vector2.h" #include "core/math/vector3i.h" #include "core/string/ustring.h" - class Basis; struct Vector3 { @@ -103,6 +103,31 @@ struct 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 move_toward(const Vector3 &p_to, const real_t p_delta) const; + _FORCE_INLINE_ Vector2 octahedron_encode() const { + Vector3 n = *this; + n /= Math::abs(n.x) + Math::abs(n.y) + Math::abs(n.z); + Vector2 o; + if (n.z >= 0.0) { + o.x = n.x; + o.y = n.y; + } else { + o.x = (1.0 - Math::abs(n.y)) * (n.x >= 0.0 ? 1.0 : -1.0); + o.y = (1.0 - Math::abs(n.x)) * (n.y >= 0.0 ? 1.0 : -1.0); + } + o.x = o.x * 0.5 + 0.5; + o.y = o.y * 0.5 + 0.5; + return o; + } + + static _FORCE_INLINE_ Vector3 octahedron_decode(const Vector2 &p_oct) { + Vector2 f(p_oct.x * 2.0 - 1.0, p_oct.y * 2.0 - 1.0); + Vector3 n(f.x, f.y, 1.0f - Math::abs(f.x) - Math::abs(f.y)); + float t = CLAMP(-n.z, 0.0, 1.0); + n.x += n.x >= 0 ? -t : t; + n.y += n.y >= 0 ? -t : t; + return n.normalized(); + } + _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; diff --git a/core/object/class_db.h b/core/object/class_db.h index d9eec4e4a8..dae75ba564 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -331,7 +331,7 @@ public: static void add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix = ""); static void add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix = ""); - static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_EDITOR); + static void add_property_array_count(const StringName &p_class, const String &p_label, const StringName &p_count_property, const StringName &p_count_setter, const StringName &p_count_getter, const String &p_array_element_prefix, uint32_t p_count_usage = PROPERTY_USAGE_DEFAULT); static void add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix); static void add_property(const StringName &p_class, const PropertyInfo &p_pinfo, const StringName &p_setter, const StringName &p_getter, int p_index = -1); static void set_property_default_value(const StringName &p_class, const StringName &p_name, const Variant &p_default); diff --git a/core/object/object.cpp b/core/object/object.cpp index b5797a4633..e7d8b0e543 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1398,7 +1398,7 @@ void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, SignalData *s = signal_map.getptr(p_signal); if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal) || - (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)); + (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal)); ERR_FAIL_COND_MSG(signal_is_valid, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'."); } ERR_FAIL_COND_MSG(!s, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string())); diff --git a/core/object/object.h b/core/object/object.h index a44d921bff..759e2ccdee 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -403,7 +403,7 @@ protected: initialize_class(); \ } \ _FORCE_INLINE_ bool (Object::*_get_get() const)(const StringName &p_name, Variant &) const { \ - return (bool (Object::*)(const StringName &, Variant &) const) & m_class::_get; \ + return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_get; \ } \ virtual bool _getv(const StringName &p_name, Variant &r_ret) const override { \ if (m_class::_get_get() != m_inherits::_get_get()) { \ @@ -414,7 +414,7 @@ protected: return m_inherits::_getv(p_name, r_ret); \ } \ _FORCE_INLINE_ bool (Object::*_get_set() const)(const StringName &p_name, const Variant &p_property) { \ - return (bool (Object::*)(const StringName &, const Variant &)) & m_class::_set; \ + return (bool(Object::*)(const StringName &, const Variant &)) & m_class::_set; \ } \ virtual bool _setv(const StringName &p_name, const Variant &p_property) override { \ if (m_inherits::_setv(p_name, p_property)) { \ @@ -426,7 +426,7 @@ protected: return false; \ } \ _FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> * p_list) const { \ - return (void (Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \ + return (void(Object::*)(List<PropertyInfo> *) const) & m_class::_get_property_list; \ } \ virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const override { \ if (!p_reversed) { \ @@ -447,7 +447,7 @@ protected: } \ } \ _FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \ - return (void (Object::*)(int)) & m_class::_notification; \ + return (void(Object::*)(int)) & m_class::_notification; \ } \ virtual void _notificationv(int p_notification, bool p_reversed) override { \ if (!p_reversed) { \ diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index 9c84c2add7..07006e7968 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -76,7 +76,7 @@ bool UndoRedo::_redo(bool p_execute) { } void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { - uint32_t ticks = OS::get_singleton()->get_ticks_msec(); + uint64_t ticks = OS::get_singleton()->get_ticks_msec(); if (action_level == 0) { _discard_redo(); diff --git a/core/os/memory.h b/core/os/memory.h index f67384a17e..ac56a12330 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -42,7 +42,6 @@ #endif class Memory { - Memory(); #ifdef DEBUG_ENABLED static SafeNumeric<uint64_t> mem_usage; static SafeNumeric<uint64_t> max_usage; diff --git a/core/os/os.cpp b/core/os/os.cpp index 7404ffdcd5..03e251880f 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -431,6 +431,24 @@ bool OS::has_feature(const String &p_feature) { if (p_feature == "arm") { return true; } +#elif defined(__riscv) +#if __riscv_xlen == 8 + if (p_feature == "rv64") { + return true; + } +#endif + if (p_feature == "riscv") { + return true; + } +#elif defined(__powerpc__) +#if defined(__powerpc64__) + if (p_feature == "ppc64") { + return true; + } +#endif + if (p_feature == "ppc") { + return true; + } #endif if (_check_internal_feature_support(p_feature)) { diff --git a/core/os/os.h b/core/os/os.h index 6d7bc47407..52bf731501 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -68,6 +68,11 @@ class OS { bool restart_on_exit = false; List<String> restart_commandline; + // for the user interface we keep a record of the current display driver + // so we can retrieve the rendering drivers available + int _display_driver_id = -1; + String _current_rendering_driver_name = ""; + protected: void _set_logger(CompositeLogger *p_logger); @@ -81,6 +86,11 @@ public: RENDER_SEPARATE_THREAD }; + enum RenderMainThreadMode { + RENDER_MAIN_THREAD_ONLY, + RENDER_ANY_THREAD, + }; + protected: friend class Main; // Needed by tests to setup command-line args. @@ -88,6 +98,7 @@ protected: HasServerFeatureCallback has_server_feature_callback = nullptr; RenderThreadMode _render_thread_mode = RENDER_THREAD_SAFE; + RenderMainThreadMode _render_main_thread_mode = RENDER_ANY_THREAD; // Functions used by Main to initialize/deinitialize the OS. void add_logger(Logger *p_logger); @@ -95,6 +106,9 @@ protected: virtual void initialize() = 0; virtual void initialize_joypads() = 0; + void set_current_rendering_driver_name(String p_driver_name) { _current_rendering_driver_name = p_driver_name; } + void set_display_driver_id(int p_display_driver_id) { _display_driver_id = p_display_driver_id; } + virtual void set_main_loop(MainLoop *p_main_loop) = 0; virtual void delete_main_loop() = 0; @@ -110,6 +124,9 @@ public: static OS *get_singleton(); + String get_current_rendering_driver_name() const { return _current_rendering_driver_name; } + int get_display_driver_id() const { return _display_driver_id; } + void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, Logger::ErrorType p_type = Logger::ERR_ERROR); void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3; @@ -134,6 +151,7 @@ public: virtual String get_executable_path() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) = 0; virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr) = 0; + virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); }; virtual Error kill(const ProcessID &p_pid) = 0; virtual int get_process_id() const; virtual void vibrate_handheld(int p_duration_ms = 500); @@ -204,8 +222,8 @@ public: String name; }; - virtual Date get_date(bool local = false) const = 0; - virtual Time get_time(bool local = false) const = 0; + virtual Date get_date(bool p_utc = false) const = 0; + virtual Time get_time(bool p_utc = false) const = 0; virtual TimeZoneInfo get_time_zone_info() const = 0; virtual double get_unix_time() const; @@ -241,6 +259,8 @@ public: virtual uint64_t get_free_static_memory() const; RenderThreadMode get_render_thread_mode() const { return _render_thread_mode; } + RenderMainThreadMode get_render_main_thread_mode() const { return _render_main_thread_mode; } + void set_render_main_thread_mode(RenderMainThreadMode p_thread_mode) { _render_main_thread_mode = p_thread_mode; } virtual String get_locale() const; String get_locale_language() const; diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp index 345371d733..adc218f597 100644 --- a/core/string/print_string.cpp +++ b/core/string/print_string.cpp @@ -69,7 +69,7 @@ void remove_print_handler(PrintHandlerList *p_handler) { ERR_FAIL_COND(l == nullptr); } -void print_line(String p_string) { +void __print_line(String p_string) { if (!_print_line_enabled) { return; } @@ -108,3 +108,7 @@ void print_verbose(String p_string) { print_line(p_string); } } + +String stringify_variants(Variant p_var) { + return p_var.operator String(); +} diff --git a/core/string/print_string.h b/core/string/print_string.h index 1a9ff1efd6..3cd170b68e 100644 --- a/core/string/print_string.h +++ b/core/string/print_string.h @@ -31,7 +31,7 @@ #ifndef PRINT_STRING_H #define PRINT_STRING_H -#include "core/string/ustring.h" +#include "core/variant/variant.h" extern void (*_print_func)(String); @@ -46,13 +46,21 @@ struct PrintHandlerList { PrintHandlerList() {} }; +String stringify_variants(Variant p_var); + +template <typename... Args> +String stringify_variants(Variant p_var, Args... p_args) { + return p_var.operator String() + " " + stringify_variants(p_args...); +} + void add_print_handler(PrintHandlerList *p_handler); void remove_print_handler(PrintHandlerList *p_handler); extern bool _print_line_enabled; extern bool _print_error_enabled; -extern void print_line(String p_string); +extern void __print_line(String p_string); extern void print_error(String p_string); extern void print_verbose(String p_string); +#define print_line(...) __print_line(stringify_variants(__VA_ARGS__)) #endif // PRINT_STRING_H diff --git a/core/string/translation.cpp b/core/string/translation.cpp index cf61467d08..6ff31a4a02 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -1563,8 +1563,8 @@ const char32_t *TranslationServer::get_accented_version(char32_t p_character) co bool TranslationServer::is_placeholder(String &p_message, int p_index) const { return p_message[p_index] == '%' && p_index < p_message.size() - 1 && - (p_message[p_index + 1] == 's' || p_message[p_index + 1] == 'c' || p_message[p_index + 1] == 'd' || - p_message[p_index + 1] == 'o' || p_message[p_index + 1] == 'x' || p_message[p_index + 1] == 'X' || p_message[p_index + 1] == 'f'); + (p_message[p_index + 1] == 's' || p_message[p_index + 1] == 'c' || p_message[p_index + 1] == 'd' || + p_message[p_index + 1] == 'o' || p_message[p_index + 1] == 'x' || p_message[p_index + 1] == 'X' || p_message[p_index + 1] == 'f'); } void TranslationServer::_bind_methods() { diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index daeb7fbd17..8d6da31cf3 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -2137,7 +2137,7 @@ int64_t String::hex_to_int() const { s++; } - if (len > 2 && s[0] == '0' && s[1] == 'x') { + if (len > 2 && s[0] == '0' && lower_case(s[1]) == 'x') { s += 2; } @@ -2151,7 +2151,7 @@ int64_t String::hex_to_int() const { } else if (c >= 'a' && c <= 'f') { n = (c - 'a') + 10; } else { - return 0; + ERR_FAIL_COND_V_MSG(true, 0, "Invalid hexadecimal notation character \"" + chr(*s) + "\" in string \"" + *this + "\"."); } // Check for overflow/underflow, with special case to ensure INT64_MIN does not result in error bool overflow = ((hex > INT64_MAX / 16) && (sign == 1 || (sign == -1 && hex != (INT64_MAX >> 4) + 1))) || (sign == -1 && hex == (INT64_MAX >> 4) + 1 && c > '0'); @@ -2178,7 +2178,7 @@ int64_t String::bin_to_int() const { s++; } - if (len > 2 && s[0] == '0' && s[1] == 'b') { + if (len > 2 && s[0] == '0' && lower_case(s[1]) == 'b') { s += 2; } @@ -2317,28 +2317,33 @@ bool String::is_numeric() const { } template <class C> -static double built_in_strtod(const C *string, /* A decimal ASCII floating-point number, - * optionally preceded by white space. Must - * have form "-I.FE-X", where I is the integer - * part of the mantissa, F is the fractional - * part of the mantissa, and X is the - * exponent. Either of the signs may be "+", - * "-", or omitted. Either I or F may be - * omitted, or both. The decimal point isn't - * necessary unless F is present. The "E" may - * actually be an "e". E and X may both be - * omitted (but not just one). */ - C **endPtr = nullptr) /* If non-nullptr, store terminating Cacter's - * address here. */ -{ - static const int maxExponent = 511; /* Largest possible base 10 exponent. Any - * exponent larger than this will already - * produce underflow or overflow, so there's - * no need to worry about additional digits. - */ - static const double powersOf10[] = { /* Table giving binary powers of 10. Entry */ - 10., /* is 10^2^i. Used to convert decimal */ - 100., /* exponents into floating-point numbers. */ +static double built_in_strtod( + /* A decimal ASCII floating-point number, + * optionally preceded by white space. Must + * have form "-I.FE-X", where I is the integer + * part of the mantissa, F is the fractional + * part of the mantissa, and X is the + * exponent. Either of the signs may be "+", + * "-", or omitted. Either I or F may be + * omitted, or both. The decimal point isn't + * necessary unless F is present. The "E" may + * actually be an "e". E and X may both be + * omitted (but not just one). */ + const C *string, + /* If non-nullptr, store terminating Cacter's + * address here. */ + C **endPtr = nullptr) { + /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. */ + static const int maxExponent = 511; + /* Table giving binary powers of 10. Entry + * is 10^2^i. Used to convert decimal + * exponents into floating-point numbers. */ + static const double powersOf10[] = { + 10., + 100., 1.0e4, 1.0e8, 1.0e16, @@ -2353,25 +2358,28 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point const double *d; const C *p; int c; - int exp = 0; /* Exponent read from "EX" field. */ - int fracExp = 0; /* Exponent that derives from the fractional - * part. Under normal circumstances, it is - * the negative of the number of digits in F. - * However, if I is very long, the last digits - * of I get dropped (otherwise a long I with a - * large negative exponent could cause an - * unnecessary overflow on I alone). In this - * case, fracExp is incremented one for each - * dropped digit. */ - int mantSize; /* Number of digits in mantissa. */ - int decPt; /* Number of mantissa digits BEFORE decimal - * point. */ - const C *pExp; /* Temporarily holds location of exponent in - * string. */ + /* Exponent read from "EX" field. */ + int exp = 0; + /* Exponent that derives from the fractional + * part. Under normal circumstances, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int fracExp = 0; + /* Number of digits in mantissa. */ + int mantSize; + /* Number of mantissa digits BEFORE decimal point. */ + int decPt; + /* Temporarily holds location of exponent in string. */ + const C *pExp; /* - * Strip off leading blanks and check for a sign. - */ + * Strip off leading blanks and check for a sign. + */ p = string; while (*p == ' ' || *p == '\t' || *p == '\n') { @@ -2388,9 +2396,9 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point } /* - * Count the number of digits in the mantissa (including the decimal - * point), and also locate the decimal point. - */ + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ decPt = -1; for (mantSize = 0;; mantSize += 1) { @@ -2405,11 +2413,11 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point } /* - * Now suck up the digits in the mantissa. Use two integers to collect 9 - * digits each (this is faster than using floating-point). If the mantissa - * has more than 18 digits, ignore the extras, since they can't affect the - * value anyway. - */ + * Now suck up the digits in the mantissa. Use two integers to collect 9 + * digits each (this is faster than using floating-point). If the mantissa + * has more than 18 digits, ignore the extras, since they can't affect the + * value anyway. + */ pExp = p; p -= mantSize; @@ -2455,8 +2463,8 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point } /* - * Skim off the exponent. - */ + * Skim off the exponent. + */ p = pExp; if ((*p == 'E') || (*p == 'e')) { @@ -2486,10 +2494,10 @@ static double built_in_strtod(const C *string, /* A decimal ASCII floating-point } /* - * Generate a floating-point number that represents the exponent. Do this - * by processing the exponent one bit at a time to combine many powers of - * 2 of 10. Then combine the exponent with the fraction. - */ + * Generate a floating-point number that represents the exponent. Do this + * by processing the exponent one bit at a time to combine many powers of + * 2 of 10. Then combine the exponent with the fraction. + */ if (exp < 0) { expSign = true; diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index 1634219c23..45e0cc2427 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -53,7 +53,7 @@ * @param RELATIONSHIP Relationship at which the hash table is resized. if amount of elements is RELATIONSHIP * times bigger than the hash table, table is resized to solve this condition. if RELATIONSHIP is zero, table is always MIN_HASH_TABLE_POWER. * -*/ + */ template <class TKey, class TData, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>, uint8_t MIN_HASH_TABLE_POWER = 3, uint8_t RELATIONSHIP = 8> class HashMap { @@ -458,8 +458,8 @@ public: * * print( *k ); * } - * - */ + * + */ const TKey *next(const TKey *p_key) const { if (unlikely(!hash_table)) { return nullptr; diff --git a/core/templates/list.h b/core/templates/list.h index c2e17a2f6f..afbed998c2 100644 --- a/core/templates/list.h +++ b/core/templates/list.h @@ -249,29 +249,29 @@ private: public: /** - * return a const iterator to the beginning of the list. - */ + * return a const iterator to the beginning of the list. + */ _FORCE_INLINE_ const Element *front() const { return _data ? _data->first : nullptr; } /** - * return an iterator to the beginning of the list. - */ + * return an iterator to the beginning of the list. + */ _FORCE_INLINE_ Element *front() { return _data ? _data->first : nullptr; } /** - * return a const iterator to the last member of the list. - */ + * return a const iterator to the last member of the list. + */ _FORCE_INLINE_ const Element *back() const { return _data ? _data->last : nullptr; } /** - * return an iterator to the last member of the list. - */ + * return an iterator to the last member of the list. + */ _FORCE_INLINE_ Element *back() { return _data ? _data->last : nullptr; } diff --git a/core/templates/ordered_hash_map.h b/core/templates/ordered_hash_map.h index 7a17eeb644..4996b88190 100644 --- a/core/templates/ordered_hash_map.h +++ b/core/templates/ordered_hash_map.h @@ -207,8 +207,12 @@ public: (*list_element)->get().second = p_value; return Element(*list_element); } - typename InternalList::Element *new_element = list.push_back(Pair<const K *, V>(nullptr, p_value)); + // Incorrectly set the first value of the pair with a value that will + // be invalid as soon as we leave this function... + typename InternalList::Element *new_element = list.push_back(Pair<const K *, V>(&p_key, p_value)); + // ...this is needed here in case the hashmap recursively reference itself... typename InternalMap::Element *e = map.set(p_key, new_element); + // ...now we can set the right value ! new_element->get().first = &e->key(); return Element(new_element); diff --git a/core/templates/vector.h b/core/templates/vector.h index 4b008a45a4..98982c80d3 100644 --- a/core/templates/vector.h +++ b/core/templates/vector.h @@ -35,7 +35,7 @@ * @class Vector * @author Juan Linietsky * Vector container. Regular Vector Container. Use with care and for smaller arrays when possible. Use Vector for large arrays. -*/ + */ #include "core/error/error_macros.h" #include "core/os/memory.h" diff --git a/core/typedefs.h b/core/typedefs.h index 8ca3d13e63..9ab874b2f0 100644 --- a/core/typedefs.h +++ b/core/typedefs.h @@ -277,6 +277,9 @@ struct BuildIndexSequence : BuildIndexSequence<N - 1, N - 1, Is...> {}; template <size_t... Is> struct BuildIndexSequence<0, Is...> : IndexSequence<Is...> {}; +// Limit the depth of recursive algorithms when dealing with Array/Dictionary +#define MAX_RECURSION 100 + #ifdef DEBUG_ENABLED #define DEBUG_METHODS_ENABLED #endif diff --git a/core/variant/array.cpp b/core/variant/array.cpp index b4d6dffc6f..69a0fff1a1 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -97,11 +97,38 @@ void Array::clear() { } bool Array::operator==(const Array &p_array) const { - return _p == p_array._p; + return recursive_equal(p_array, 0); } bool Array::operator!=(const Array &p_array) const { - return !operator==(p_array); + return !recursive_equal(p_array, 0); +} + +bool Array::recursive_equal(const Array &p_array, int recursion_count) const { + // Cheap checks + if (_p == p_array._p) { + return true; + } + const Vector<Variant> &a1 = _p->array; + const Vector<Variant> &a2 = p_array._p->array; + const int size = a1.size(); + if (size != a2.size()) { + return false; + } + + // Heavy O(n) check + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return true; + } + recursion_count++; + for (int i = 0; i < size; i++) { + if (!a1[i].hash_compare(a2[i], recursion_count)) { + return false; + } + } + + return true; } bool Array::operator<(const Array &p_array) const { @@ -132,10 +159,20 @@ bool Array::operator>=(const Array &p_array) const { } uint32_t Array::hash() const { - uint32_t h = hash_djb2_one_32(0); + return recursive_hash(0); +} +uint32_t Array::recursive_hash(int recursion_count) const { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return 0; + } + + uint32_t h = hash_djb2_one_32(Variant::ARRAY); + + recursion_count++; for (int i = 0; i < _p->array.size(); i++) { - h = hash_djb2_one_32(_p->array[i].hash(), h); + h = hash_djb2_one_32(_p->array[i].recursive_hash(recursion_count), h); } return h; } @@ -300,12 +337,29 @@ const Variant &Array::get(int p_idx) const { } Array Array::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +Array Array::recursive_duplicate(bool p_deep, int recursion_count) const { Array new_arr; + + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return new_arr; + } + int element_count = size(); new_arr.resize(element_count); new_arr._p->typed = _p->typed; - for (int i = 0; i < element_count; i++) { - new_arr[i] = p_deep ? get(i).duplicate(p_deep) : get(i); + if (p_deep) { + recursion_count++; + for (int i = 0; i < element_count; i++) { + new_arr[i] = get(i).recursive_duplicate(true, recursion_count); + } + } else { + for (int i = 0; i < element_count; i++) { + new_arr[i] = get(i); + } } return new_arr; diff --git a/core/variant/array.h b/core/variant/array.h index 4a1b25c4a9..bd39b8e0b1 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -63,8 +63,10 @@ public: bool operator==(const Array &p_array) const; bool operator!=(const Array &p_array) const; + bool recursive_equal(const Array &p_array, int recursion_count) const; uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; void operator=(const Array &p_array); void push_back(const Variant &p_value); @@ -100,6 +102,7 @@ public: Variant pop_at(int p_pos); Array duplicate(bool p_deep = false) const; + Array recursive_duplicate(bool p_deep, int recursion_count) const; Array slice(int p_begin, int p_end, int p_step = 1, bool p_deep = false) const; Array filter(const Callable &p_callable) const; diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 8592a1dc62..f06d767cf5 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -88,6 +88,7 @@ struct VariantCaster<const T &> { VARIANT_ENUM_CAST(Object::ConnectFlags); VARIANT_ENUM_CAST(Vector3::Axis); +VARIANT_ENUM_CAST(Basis::EulerOrder); VARIANT_ENUM_CAST(Error); VARIANT_ENUM_CAST(Side); diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index 07b3a9a675..24d21386a7 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -188,11 +188,35 @@ bool Dictionary::erase(const Variant &p_key) { } bool Dictionary::operator==(const Dictionary &p_dictionary) const { - return _p == p_dictionary._p; + return recursive_equal(p_dictionary, 0); } bool Dictionary::operator!=(const Dictionary &p_dictionary) const { - return _p != p_dictionary._p; + return !recursive_equal(p_dictionary, 0); +} + +bool Dictionary::recursive_equal(const Dictionary &p_dictionary, int recursion_count) const { + // Cheap checks + if (_p == p_dictionary._p) { + return true; + } + if (_p->variant_map.size() != p_dictionary._p->variant_map.size()) { + return false; + } + + // Heavy O(n) check + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return true; + } + recursion_count++; + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement this_E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->front(); this_E; this_E = this_E.next()) { + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement other_E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&p_dictionary._p->variant_map)->find(this_E.key()); + if (!other_E || !this_E.value().hash_compare(other_E.value(), recursion_count)) { + return false; + } + } + return true; } void Dictionary::_ref(const Dictionary &p_from) const { @@ -225,11 +249,21 @@ void Dictionary::_unref() const { } uint32_t Dictionary::hash() const { + return recursive_hash(0); +} + +uint32_t Dictionary::recursive_hash(int recursion_count) const { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return 0; + } + uint32_t h = hash_djb2_one_32(Variant::DICTIONARY); + recursion_count++; for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { - h = hash_djb2_one_32(E.key().hash(), h); - h = hash_djb2_one_32(E.value().hash(), h); + h = hash_djb2_one_32(E.key().recursive_hash(recursion_count), h); + h = hash_djb2_one_32(E.value().recursive_hash(recursion_count), h); } return h; @@ -286,10 +320,26 @@ const Variant *Dictionary::next(const Variant *p_key) const { } Dictionary Dictionary::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +Dictionary Dictionary::recursive_duplicate(bool p_deep, int recursion_count) const { Dictionary n; - for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { - n[E.key()] = p_deep ? E.value().duplicate(true) : E.value(); + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + return n; + } + + if (p_deep) { + recursion_count++; + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + n[E.key().recursive_duplicate(true, recursion_count)] = E.value().recursive_duplicate(true, recursion_count); + } + } else { + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + n[E.key()] = E.value(); + } } return n; diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h index 4067ff9fd9..f8a2a7573f 100644 --- a/core/variant/dictionary.h +++ b/core/variant/dictionary.h @@ -70,8 +70,10 @@ public: bool operator==(const Dictionary &p_dictionary) const; bool operator!=(const Dictionary &p_dictionary) const; + bool recursive_equal(const Dictionary &p_dictionary, int recursion_count) const; uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; void operator=(const Dictionary &p_dictionary); const Variant *next(const Variant *p_key = nullptr) const; @@ -80,6 +82,7 @@ public: Array values() const; Dictionary duplicate(bool p_deep = false) const; + Dictionary recursive_duplicate(bool p_deep, int recursion_count) const; const void *id() const; diff --git a/core/variant/type_info.h b/core/variant/type_info.h index b70d29bbac..2c6b82d25f 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -60,7 +60,7 @@ struct TypeInherits { static char (&test(...))[2]; static bool const value = sizeof(test(get_d())) == sizeof(char) && - !TypesAreSame<B volatile const, void volatile const>::value; + !TypesAreSame<B volatile const, void volatile const>::value; }; namespace GodotTypeInfo { diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 3214fc125d..c43ff8626e 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -313,7 +313,6 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { case BASIS: { static const Type valid[] = { QUATERNION, - VECTOR3, NIL }; @@ -620,7 +619,6 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type case BASIS: { static const Type valid[] = { QUATERNION, - VECTOR3, NIL }; @@ -786,16 +784,11 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } bool Variant::operator==(const Variant &p_variant) const { - if (type != p_variant.type) { //evaluation of operator== needs to be more strict - return false; - } - bool v; - Variant r; - evaluate(OP_EQUAL, *this, p_variant, r, v); - return r; + return hash_compare(p_variant); } bool Variant::operator!=(const Variant &p_variant) const { + // Don't use `!hash_compare(p_variant)` given it makes use of OP_EQUAL if (type != p_variant.type) { //evaluation of operator== needs to be more strict return true; } @@ -1619,25 +1612,23 @@ struct _VariantStrPair { }; Variant::operator String() const { - List<const void *> stack; - - return stringify(stack); + return stringify(0); } template <class T> -String stringify_vector(const T &vec, List<const void *> &stack) { +String stringify_vector(const T &vec, int recursion_count) { String str("["); for (int i = 0; i < vec.size(); i++) { if (i > 0) { str += ", "; } - str = str + Variant(vec[i]).stringify(stack); + str = str + Variant(vec[i]).stringify(recursion_count); } str += "]"; return str; } -String Variant::stringify(List<const void *> &stack) const { +String Variant::stringify(int recursion_count) const { switch (type) { case NIL: return "null"; @@ -1681,23 +1672,22 @@ String Variant::stringify(List<const void *> &stack) const { return operator Color(); case DICTIONARY: { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); - if (stack.find(d.id())) { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); return "{...}"; } - stack.push_back(d.id()); - - //const String *K=nullptr; String str("{"); List<Variant> keys; d.get_key_list(&keys); Vector<_VariantStrPair> pairs; - for (const Variant &E : keys) { + recursion_count++; + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { _VariantStrPair sp; - sp.key = E.stringify(stack); - sp.value = d[E].stringify(stack); + sp.key = E->get().stringify(recursion_count); + sp.value = d[E->get()].stringify(recursion_count); pairs.push_back(sp); } @@ -1712,46 +1702,43 @@ String Variant::stringify(List<const void *> &stack) const { } str += "}"; - stack.erase(d.id()); return str; } break; case PACKED_VECTOR2_ARRAY: { - return stringify_vector(operator Vector<Vector2>(), stack); + return stringify_vector(operator Vector<Vector2>(), recursion_count); } break; case PACKED_VECTOR3_ARRAY: { - return stringify_vector(operator Vector<Vector3>(), stack); + return stringify_vector(operator Vector<Vector3>(), recursion_count); } break; case PACKED_COLOR_ARRAY: { - return stringify_vector(operator Vector<Color>(), stack); + return stringify_vector(operator Vector<Color>(), recursion_count); } break; case PACKED_STRING_ARRAY: { - return stringify_vector(operator Vector<String>(), stack); + return stringify_vector(operator Vector<String>(), recursion_count); } break; case PACKED_BYTE_ARRAY: { - return stringify_vector(operator Vector<uint8_t>(), stack); + return stringify_vector(operator Vector<uint8_t>(), recursion_count); } break; case PACKED_INT32_ARRAY: { - return stringify_vector(operator Vector<int32_t>(), stack); + return stringify_vector(operator Vector<int32_t>(), recursion_count); } break; case PACKED_INT64_ARRAY: { - return stringify_vector(operator Vector<int64_t>(), stack); + return stringify_vector(operator Vector<int64_t>(), recursion_count); } break; case PACKED_FLOAT32_ARRAY: { - return stringify_vector(operator Vector<float>(), stack); + return stringify_vector(operator Vector<float>(), recursion_count); } break; case PACKED_FLOAT64_ARRAY: { - return stringify_vector(operator Vector<double>(), stack); + return stringify_vector(operator Vector<double>(), recursion_count); } break; case ARRAY: { Array arr = operator Array(); - if (stack.find(arr.id())) { + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); return "[...]"; } - stack.push_back(arr.id()); - - String str = stringify_vector(arr, stack); - stack.erase(arr.id()); + String str = stringify_vector(arr, recursion_count); return str; } break; @@ -1889,8 +1876,6 @@ Variant::operator Basis() const { return *_data._basis; } else if (type == QUATERNION) { return *reinterpret_cast<const Quaternion *>(_data._mem); - } else if (type == VECTOR3) { - return Basis(*reinterpret_cast<const Vector3 *>(_data._mem)); } else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert? return _data._transform3d->basis; } else { @@ -2772,6 +2757,10 @@ Variant::Variant(const Variant &p_variant) { } uint32_t Variant::hash() const { + return recursive_hash(0); +} + +uint32_t Variant::recursive_hash(int recursion_count) const { switch (type) { case NIL: { return 0; @@ -2899,7 +2888,7 @@ uint32_t Variant::hash() const { return reinterpret_cast<const NodePath *>(_data._mem)->hash(); } break; case DICTIONARY: { - return reinterpret_cast<const Dictionary *>(_data._mem)->hash(); + return reinterpret_cast<const Dictionary *>(_data._mem)->recursive_hash(recursion_count); } break; case CALLABLE: { @@ -2913,7 +2902,7 @@ uint32_t Variant::hash() const { } break; case ARRAY: { const Array &arr = *reinterpret_cast<const Array *>(_data._mem); - return arr.hash(); + return arr.recursive_hash(recursion_count); } break; case PACKED_BYTE_ARRAY: { @@ -3087,7 +3076,7 @@ uint32_t Variant::hash() const { \ return true -bool Variant::hash_compare(const Variant &p_variant) const { +bool Variant::hash_compare(const Variant &p_variant, int recursion_count) const { if (type != p_variant.type) { return false; } @@ -3122,7 +3111,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { const Rect2 *r = reinterpret_cast<const Rect2 *>(p_variant._data._mem); return (hash_compare_vector2(l->position, r->position)) && - (hash_compare_vector2(l->size, r->size)); + (hash_compare_vector2(l->size, r->size)); } break; case RECT2I: { const Rect2i *l = reinterpret_cast<const Rect2i *>(_data._mem); @@ -3162,7 +3151,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { const Plane *r = reinterpret_cast<const Plane *>(p_variant._data._mem); return (hash_compare_vector3(l->normal, r->normal)) && - (hash_compare_scalar(l->d, r->d)); + (hash_compare_scalar(l->d, r->d)); } break; case AABB: { @@ -3218,14 +3207,19 @@ bool Variant::hash_compare(const Variant &p_variant) const { const Array &l = *(reinterpret_cast<const Array *>(_data._mem)); const Array &r = *(reinterpret_cast<const Array *>(p_variant._data._mem)); - if (l.size() != r.size()) { + if (!l.recursive_equal(r, recursion_count + 1)) { return false; } - for (int i = 0; i < l.size(); ++i) { - if (!l[i].hash_compare(r[i])) { - return false; - } + return true; + } break; + + case DICTIONARY: { + const Dictionary &l = *(reinterpret_cast<const Dictionary *>(_data._mem)); + const Dictionary &r = *(reinterpret_cast<const Dictionary *>(p_variant._data._mem)); + + if (!l.recursive_equal(r, recursion_count + 1)) { + return false; } return true; diff --git a/core/variant/variant.h b/core/variant/variant.h index d3f694e7ca..8ce5e7dcd2 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -481,7 +481,8 @@ public: static PTROperatorEvaluator get_ptr_operator_evaluator(Operator p_operator, Type p_type_a, Type p_type_b); void zero(); - Variant duplicate(bool deep = false) const; + Variant duplicate(bool p_deep = false) const; + Variant recursive_duplicate(bool p_deep, int recursion_count) const; static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst); static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst); @@ -659,10 +660,11 @@ public: bool operator!=(const Variant &p_variant) const; bool operator<(const Variant &p_variant) const; uint32_t hash() const; + uint32_t recursive_hash(int recursion_count) const; - bool hash_compare(const Variant &p_variant) const; + bool hash_compare(const Variant &p_variant, int recursion_count = 0) const; bool booleanize() const; - String stringify(List<const void *> &stack) const; + String stringify(int recursion_count = 0) const; String to_json_string() const; void static_assign(const Variant &p_variant); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 6284caae2d..2b1d330942 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1366,6 +1366,7 @@ static void _register_variant_builtin_methods() { bind_method(String, naturalnocasecmp_to, sarray("to"), varray()); bind_method(String, length, sarray(), varray()); bind_method(String, substr, sarray("from", "len"), varray(-1)); + bind_method(String, get_slice, sarray("delimiter", "slice"), varray()); bind_methodv(String, find, static_cast<int (String::*)(const String &, int) const>(&String::find), sarray("what", "from"), varray(0)); bind_method(String, count, sarray("what", "from", "to"), varray(0, 0)); bind_method(String, countn, sarray("what", "from", "to"), varray(0, 0)); @@ -1581,6 +1582,8 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, bounce, sarray("n"), varray()); bind_method(Vector3, reflect, sarray("n"), varray()); bind_method(Vector3, sign, sarray(), varray()); + bind_method(Vector3, octahedron_encode, sarray(), varray()); + bind_static_method(Vector3, octahedron_decode, sarray("uv"), varray()); /* Vector3i */ @@ -1617,6 +1620,8 @@ static void _register_variant_builtin_methods() { bind_method(Quaternion, slerpni, sarray("to", "weight"), varray()); bind_method(Quaternion, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); bind_method(Quaternion, get_euler, sarray(), varray()); + bind_method(Quaternion, get_axis, sarray(), varray()); + bind_method(Quaternion, get_angle, sarray(), varray()); /* Color */ @@ -1727,7 +1732,7 @@ static void _register_variant_builtin_methods() { bind_methodv(Basis, rotated, static_cast<Basis (Basis::*)(const Vector3 &, real_t) const>(&Basis::rotated), sarray("axis", "phi"), varray()); bind_method(Basis, scaled, sarray("scale"), varray()); bind_method(Basis, get_scale, sarray(), varray()); - bind_method(Basis, get_euler, sarray(), varray()); + bind_method(Basis, get_euler, sarray("order"), varray(Basis::EULER_ORDER_YXZ)); bind_method(Basis, tdotx, sarray("with"), varray()); bind_method(Basis, tdoty, sarray("with"), varray()); bind_method(Basis, tdotz, sarray("with"), varray()); @@ -1737,6 +1742,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, get_rotation_quaternion, sarray(), varray()); bind_static_method(Basis, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); bind_static_method(Basis, from_scale, sarray("scale"), varray()); + bind_static_method(Basis, from_euler, sarray("euler", "order"), varray(Basis::EULER_ORDER_YXZ)); /* AABB */ @@ -2105,6 +2111,13 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1)); _VariantCall::add_variant_constant(Variant::VECTOR2I, "DOWN", Vector2i(0, 1)); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY); + _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX); + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D()); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index 6aba7d7d58..5c14f30180 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -128,10 +128,10 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Quaternion>>(sarray()); add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from")); add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle")); add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to")); add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w")); + add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler_yxz")); add_constructor<VariantConstructNoArgs<::AABB>>(sarray()); add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from")); @@ -140,7 +140,6 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Basis>>(sarray()); add_constructor<VariantConstructor<Basis, Basis>>(sarray("from")); add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from")); - add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi")); add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis")); diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index 37383ff2ec..2ba24b5af8 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -757,6 +757,12 @@ VARIANT_ACCESSOR_NUMBER(Error) VARIANT_ACCESSOR_NUMBER(Side) template <> +struct VariantInternalAccessor<Basis::EulerOrder> { + static _FORCE_INLINE_ Basis::EulerOrder get(const Variant *v) { return Basis::EulerOrder(*VariantInternal::get_int(v)); } + static _FORCE_INLINE_ void set(Variant *v, Basis::EulerOrder p_value) { *VariantInternal::get_int(v) = p_value; } +}; + +template <> struct VariantInternalAccessor<ObjectID> { static _FORCE_INLINE_ ObjectID get(const Variant *v) { return ObjectID(*VariantInternal::get_int(v)); } static _FORCE_INLINE_ void set(Variant *v, ObjectID p_value) { *VariantInternal::get_int(v) = p_value; } diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index 221a8c4f98..3c19c2c706 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -1443,7 +1443,7 @@ static String rtos_fix(double p_value) { } } -Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) { +Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count) { switch (p_variant.get_type()) { case Variant::NIL: { p_store_string_func(p_store_string_ud, "null"); @@ -1639,41 +1639,56 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str case Variant::DICTIONARY: { Dictionary dict = p_variant; - - List<Variant> keys; - dict.get_key_list(&keys); - keys.sort(); - - p_store_string_func(p_store_string_ud, "{\n"); - for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { - /* - if (!_check_type(dict[E])) - continue; - */ - write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); - p_store_string_func(p_store_string_ud, ": "); - write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); - if (E->next()) { - p_store_string_func(p_store_string_ud, ",\n"); - } else { - p_store_string_func(p_store_string_ud, "\n"); + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "{}"); + } else { + recursion_count++; + + List<Variant> keys; + dict.get_key_list(&keys); + keys.sort(); + + p_store_string_func(p_store_string_ud, "{\n"); + for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { + /* + if (!_check_type(dict[E->get()])) + continue; + */ + write(E->get(), p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + p_store_string_func(p_store_string_ud, ": "); + write(dict[E->get()], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); + if (E->next()) { + p_store_string_func(p_store_string_ud, ",\n"); + } else { + p_store_string_func(p_store_string_ud, "\n"); + } } - } - p_store_string_func(p_store_string_ud, "}"); + p_store_string_func(p_store_string_ud, "}"); + } } break; + case Variant::ARRAY: { - p_store_string_func(p_store_string_ud, "["); - Array array = p_variant; - int len = array.size(); - for (int i = 0; i < len; i++) { - if (i > 0) { - p_store_string_func(p_store_string_ud, ", "); + if (recursion_count > MAX_RECURSION) { + ERR_PRINT("Max recursion reached"); + p_store_string_func(p_store_string_ud, "[]"); + } else { + recursion_count++; + + p_store_string_func(p_store_string_ud, "["); + Array array = p_variant; + int len = array.size(); + for (int i = 0; i < len; i++) { + if (i > 0) { + p_store_string_func(p_store_string_ud, ", "); + } + write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud, recursion_count); } - write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); + + p_store_string_func(p_store_string_ud, "]"); } - p_store_string_func(p_store_string_ud, "]"); } break; diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 1ba26db6ed..2e4baa6fff 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -140,7 +140,7 @@ public: typedef Error (*StoreStringFunc)(void *ud, const String &p_string); typedef String (*EncodeResourceFunc)(void *ud, const RES &p_resource); - static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud); + static Error write(const Variant &p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud, int recursion_count = 0); static Error write_to_string(const Variant &p_variant, String &r_string, EncodeResourceFunc p_encode_res_func = nullptr, void *p_encode_res_ud = nullptr); }; diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 4abb51ca7c..2530d77c62 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -1824,11 +1824,15 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { return Variant(); } -Variant Variant::duplicate(bool deep) const { +Variant Variant::duplicate(bool p_deep) const { + return recursive_duplicate(p_deep, 0); +} + +Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const { switch (type) { case OBJECT: { /* breaks stuff :( - if (deep && !_get_obj().ref.is_null()) { + if (p_deep && !_get_obj().ref.is_null()) { Ref<Resource> resource = _get_obj().ref; if (resource.is_valid()) { return resource->duplicate(true); @@ -1838,9 +1842,9 @@ Variant Variant::duplicate(bool deep) const { return *this; } break; case DICTIONARY: - return operator Dictionary().duplicate(deep); + return operator Dictionary().recursive_duplicate(p_deep, recursion_count); case ARRAY: - return operator Array().duplicate(deep); + return operator Array().recursive_duplicate(p_deep, recursion_count); case PACKED_BYTE_ARRAY: return operator Vector<uint8_t>().duplicate(); case PACKED_INT32_ARRAY: |